Running yarn generate-openapi-client today no longer regenerates the typed client; it silently produces an all-any one. The pinned generator (6.2.1) predates OpenAPI 3.1, but https://api.permit.io/v2/openapi.json is now 3.1.0, so 6.2.1 fails to resolve most schemas and emits untyped output. Because the script passes --skip-validate-spec, the run still exits 0. The committed src/openapi/ is clean and typed, but it can't be reproduced from the live spec anymore, so new schema fields (role inheritance via RoleCreate.extends, and anything else added recently) can't be regenerated cleanly.
- Other information (e.g. detailed explanation, stack traces, related issues, suggestions how to fix, links for us to have context, eg. StackOverflow, personal fork, etc.)
Reproduction (clean checkout, yarn install, then yarn generate-openapi-client):
The pin is 6.2.1:
// openapitools.json
"generator-cli": { "version": "6.2.1" }
and the script targets the live spec with validation off:
openapi-generator-cli generate -i https://api.permit.io/v2/openapi.json -g typescript-axios ... --skip-validate-spec
The live spec declares "openapi": "3.1.0", which 6.2.1's parser can't read. The run logs 82 resolver errors across 15 distinct schemas, all with the same Jackson root cause:
[main] ERROR i.s.v.p.reference.ReferenceVisitor - Error resolving schema #/components/schemas/ResourceRead
...
java.lang.IllegalArgumentException: Cannot deserialize value of type `java.lang.Boolean` from Object value (token `JsonToken.START_OBJECT`)
Affected schemas include ResourceRead, ResourceCreate, ResourceReplace, ResourceUpdate, ElementsConfigRead/Create/Update, MappingRule(Update), and the OPAL data models. With --skip-validate-spec set, the generator exits 0 and writes files anyway, but every member that depended on an unresolved schema degrades to any. A fresh regen degrades 247 of 319 generated type files to all-any.
RoleCreate shows the failure cleanly. The two blocks below are the same live spec fed to 6.2.1, differing only in the top-level openapi version string (so they isolate the version bug from any unrelated drift; keys are quoted because the script later runs yarn fix:prettier). With the version header rewritten to 3.0.3, 6.2.1 types every property correctly:
export interface RoleCreate {
'key': string;
'name': string;
'description'?: string;
'permissions'?: Array<string>;
'attributes'?: object;
'extends'?: Array<string>;
'granted_to'?: GrantedTo;
'v1compat_settings'?: object;
'v1compat_attributes'?: object;
'v1compat_is_built_in'?: boolean;
}
Left at 3.1.0, the byte-identical content collapses to any under an index signature, exit 0:
export interface RoleCreate {
[key: string]: any;
'key': any;
'name': any;
'description'?: any;
'permissions'?: any;
'attributes'?: any;
'extends'?: any;
'granted_to'?: any;
'v1compat_settings'?: any;
'v1compat_attributes'?: any;
'v1compat_is_built_in'?: any;
}
(The committed src/openapi/types/role-create.ts has the typed shape but only 6 of these properties, with no extends. It was generated against an older 3.0 spec, before extends and the v1compat_* fields were added, which is the regeneration gap this issue is about.)
Root cause
The generator is pinned to 6.2.1, which predates OpenAPI 3.1. The spec moved from 3.0 to 3.1, so 6.2.1 can't model it. The Boolean from Object resolver errors are the visible symptom but not the main driver: a clean schema that logs no resolver error still degrades. A minimal one-property 3.1 spec with no $ref (or RoleCreate itself) still turns every property into any; the codegen receives an effectively empty schema for it, while the byte-identical 3.0.3 content types correctly. So 6.2.1 does not recover a usable type from the 2020-12 representation. (The exact internal accessor that drops the type is a likely-but-unconfirmed mechanism; the observable above is what I verified.) --skip-validate-spec then turns what should be a hard failure into a silent exit 0. The committed src/openapi/ was generated by 6.2.1 against an earlier 3.0 spec, which is why it's still clean, but that path can't be reproduced today.
Options (directions to weigh, not a recommendation; I'd implement whichever you prefer)
A. Downconvert the spec to 3.0 before generation, keep 6.2.1. Rewrite the top-level openapi header from 3.1.0 to 3.0.3 ahead of the unchanged generator. Smallest change, and it restores typed output for the spec as it is today (verified: the current spec re-declared 3.0.3 produces 0 all-any). Caveat, verified locally: this only changes the version string, it does not transform 3.1 / JSON-Schema-2020-12 constructs. A property typed ["string","null"] (nullable union), a const, or an array with items: {type: ["string","null"]} still degrades to any (exit 0) after the downconvert. So it's a minimal bridge that holds only while the spec stays 3.0-representable; the moment a genuinely-3.1 type lands, it silently regresses to the same any.
B. Move to a 3.1-capable generator (e.g. 7.12.0). This is the only lever that models 3.1 natively, so it closes the failure for the constructs above instead of relying on the spec staying 3.0-shaped. Not every 7.x is usable: 7.1.0 and 7.5.0 both fail with a NullPointerException (7.1.0 writes a partial, still-mistyped client, e.g. RoleCreate.key: any, before exiting non-zero; 7.5.0 exits non-zero and writes nothing). 7.12.0 is the first that types the client. Trade-offs: a 6.x to 7.x bump changes some typescript-axios output (worth a careful diff of the regenerated client), and 7.12.0 has a small residual of its own, 2 of 350 types still come out all-any (derived-role-rule-create, derived-role-block-edit), a separate and narrower matter.
C. Add a codegen check in CI, whichever lever you pick. Regenerate the client and assert it still carries named types (no [key: string]: any). This is the gap that kept the breakage invisible: nothing runs generate-openapi-client in CI today, and an all-any client compiles and lints clean (strict doesn't flag explicit any). Two things make it a real guard rather than a snapshot check. Run it against the live spec (or a fixture you refresh on a schedule) so it can see drift, and note it needs the Java / openapi-generator toolchain available in CI.
On --skip-validate-spec: dropping it would surface the failure, but heads-up that the served spec also has two unrelated authoring issues, a duplicate Bulk Operations tag and a tuple-form (array) items nested in OPALUpdateCallback that isn't valid OpenAPI 3.0, so validation currently fails fast on those too. The codegen check above is a cleaner fail-loud signal.
Separately, regenerating against the live spec also surfaces drift since the committed client was last built (e.g. src/api/elements.ts references an AuthenticationApi the live API no longer exposes), so a full re-baseline is probably its own change rather than part of this fix.
Happy to send a PR for whichever direction you prefer.
I'm submitting a ...
[x] bug report
[ ] feature request
[ ] question about the decisions made in the repository
[ ] question about how to use this project
Summary
Running
yarn generate-openapi-clienttoday no longer regenerates the typed client; it silently produces an all-anyone. The pinned generator (6.2.1) predates OpenAPI 3.1, buthttps://api.permit.io/v2/openapi.jsonis now3.1.0, so 6.2.1 fails to resolve most schemas and emits untyped output. Because the script passes--skip-validate-spec, the run still exits 0. The committedsrc/openapi/is clean and typed, but it can't be reproduced from the live spec anymore, so new schema fields (role inheritance viaRoleCreate.extends, and anything else added recently) can't be regenerated cleanly.Reproduction (clean checkout,
yarn install, thenyarn generate-openapi-client):The pin is 6.2.1:
and the script targets the live spec with validation off:
The live spec declares
"openapi": "3.1.0", which 6.2.1's parser can't read. The run logs 82 resolver errors across 15 distinct schemas, all with the same Jackson root cause:Affected schemas include
ResourceRead,ResourceCreate,ResourceReplace,ResourceUpdate,ElementsConfigRead/Create/Update,MappingRule(Update), and the OPAL data models. With--skip-validate-specset, the generator exits 0 and writes files anyway, but every member that depended on an unresolved schema degrades toany. A fresh regen degrades 247 of 319 generated type files to all-any.RoleCreateshows the failure cleanly. The two blocks below are the same live spec fed to 6.2.1, differing only in the top-levelopenapiversion string (so they isolate the version bug from any unrelated drift; keys are quoted because the script later runsyarn fix:prettier). With the version header rewritten to3.0.3, 6.2.1 types every property correctly:Left at
3.1.0, the byte-identical content collapses toanyunder an index signature, exit 0:(The committed
src/openapi/types/role-create.tshas the typed shape but only 6 of these properties, with noextends. It was generated against an older 3.0 spec, beforeextendsand thev1compat_*fields were added, which is the regeneration gap this issue is about.)Root cause
The generator is pinned to 6.2.1, which predates OpenAPI 3.1. The spec moved from 3.0 to 3.1, so 6.2.1 can't model it. The
Boolean from Objectresolver errors are the visible symptom but not the main driver: a clean schema that logs no resolver error still degrades. A minimal one-property 3.1 spec with no$ref(orRoleCreateitself) still turns every property intoany; the codegen receives an effectively empty schema for it, while the byte-identical 3.0.3 content types correctly. So 6.2.1 does not recover a usable type from the 2020-12 representation. (The exact internal accessor that drops the type is a likely-but-unconfirmed mechanism; the observable above is what I verified.)--skip-validate-specthen turns what should be a hard failure into a silent exit 0. The committedsrc/openapi/was generated by 6.2.1 against an earlier 3.0 spec, which is why it's still clean, but that path can't be reproduced today.Options (directions to weigh, not a recommendation; I'd implement whichever you prefer)
A. Downconvert the spec to 3.0 before generation, keep 6.2.1. Rewrite the top-level
openapiheader from3.1.0to3.0.3ahead of the unchanged generator. Smallest change, and it restores typed output for the spec as it is today (verified: the current spec re-declared3.0.3produces 0 all-any). Caveat, verified locally: this only changes the version string, it does not transform 3.1 / JSON-Schema-2020-12 constructs. A property typed["string","null"](nullable union), aconst, or an array withitems: {type: ["string","null"]}still degrades toany(exit 0) after the downconvert. So it's a minimal bridge that holds only while the spec stays 3.0-representable; the moment a genuinely-3.1 type lands, it silently regresses to the sameany.B. Move to a 3.1-capable generator (e.g.
7.12.0). This is the only lever that models 3.1 natively, so it closes the failure for the constructs above instead of relying on the spec staying 3.0-shaped. Not every 7.x is usable:7.1.0and7.5.0both fail with aNullPointerException(7.1.0writes a partial, still-mistyped client, e.g.RoleCreate.key: any, before exiting non-zero;7.5.0exits non-zero and writes nothing).7.12.0is the first that types the client. Trade-offs: a 6.x to 7.x bump changes some typescript-axios output (worth a careful diff of the regenerated client), and7.12.0has a small residual of its own, 2 of 350 types still come out all-any(derived-role-rule-create,derived-role-block-edit), a separate and narrower matter.C. Add a codegen check in CI, whichever lever you pick. Regenerate the client and assert it still carries named types (no
[key: string]: any). This is the gap that kept the breakage invisible: nothing runsgenerate-openapi-clientin CI today, and an all-anyclient compiles and lints clean (strictdoesn't flag explicitany). Two things make it a real guard rather than a snapshot check. Run it against the live spec (or a fixture you refresh on a schedule) so it can see drift, and note it needs the Java / openapi-generator toolchain available in CI.On
--skip-validate-spec: dropping it would surface the failure, but heads-up that the served spec also has two unrelated authoring issues, a duplicateBulk Operationstag and a tuple-form (array)itemsnested inOPALUpdateCallbackthat isn't valid OpenAPI 3.0, so validation currently fails fast on those too. The codegen check above is a cleaner fail-loud signal.Separately, regenerating against the live spec also surfaces drift since the committed client was last built (e.g.
src/api/elements.tsreferences anAuthenticationApithe live API no longer exposes), so a full re-baseline is probably its own change rather than part of this fix.Happy to send a PR for whichever direction you prefer.