Troubleshooting
Something stopped, warned or produced code that does not behave as expected. This page lists the messages the generators print and the failures you can see later in a build or a test run, each with its cause and the change that fixes it, grouped by the phase in which they appear. The messages are quoted as the 2.0.0 generators print them.
Configuration
Configuration errors stop the run before anything is written. The message names the file and the field, and ends with the same four-line checklist every time:
Invalid configuration file at: /home/me/project/openapi-to-zod.config.json
Validation errors:
- specs.0: Unrecognized key 'stripPrefix'. Check for typos in field names.
Please check your configuration file and ensure:
- All required fields are present (specs array with input/outputTypes)
- Field names are spelled correctly (no typos)
- Values match the expected types (e.g., mode: 'strict' | 'normal' | 'loose')
- No unknown/extra properties are included
| Symptom | Cause | Fix |
|---|---|---|
No config file found. Searched for: openapi-to-zod.config.ts, openapi-to-zod.config.json, package.json (openapi-to-zod key) | The command searched upwards from the current directory and found no file with one of those names. | Run from the project directory, pass --config <path>, or create a file with npx openapi-to-zod init. |
Config file not found at: ./config/zod.config.ts | The --config path does not exist. | Check the path; it is resolved from the current directory. |
specs.0: Unrecognized key 'stripPrefix'. Check for typos in field names. | The option does not exist for this generator. Every option is spelled as in its reference page; options of one generator are rejected by another. | Look the option up in the generator's reference (TypeScript, Zod, Playwright, k6); here stripSchemaPrefix was meant. |
defaults: Unrecognized key 'outputTypes'. together with specs.0.outputTypes: Each spec must specify an output file path using 'outputTypes' (preferred) or deprecated 'output'. | An output path was put in defaults. Paths are per spec, otherwise every spec would write the same file. | Move input, outputTypes, outputZodSchemas, outputClient and outputService into each entry of specs. |
specs.0.outputTypes: Missing 'outputTypes'. Each spec must specify an output file path for generated TypeScript types. and Unrecognized key 'output'. Did you mean 'outputTypes'? The 'output' field was renamed to 'outputTypes'. | The TypeScript and k6 generators do not accept the old output key. The Zod and Playwright generators still accept it as a deprecated alias of outputTypes. | Rename output to outputTypes. |
specs.0.enumFormat: Invalid value '["union","const-object"]'. Expected one of: union, const-object | enumFormat: "enum" was set for the Zod or Playwright generator. A TypeScript enum cannot be the type of a Zod schema, so only union and const-object are accepted there. | Use union or const-object; enum is available in the TypeScript and k6 generators. See Option parity. |
specs.0: Unrecognized key 'schemaType'. from openapi-to-k6 or openapi-to-zod-playwright | schemaType exists for the TypeScript and Zod generators only. A k6 client sends and receives with the same types, and the Playwright generator chooses the direction per schema itself. | Remove the key; see Request and response shapes. |
specs: Configuration must include at least one specification. | specs is empty. | Add at least one { input, outputTypes, ... } entry. |
Cannot load ./openapi-to-typescript.config.ts: the module '@acme/not-installed-here' is not installed. followed by Install it where the config lives, or switch to a JSON config that needs no imports. | A .ts config imports a package that is not installed in the directory the config lives in, typically because npm install has not run there or the generator is run from another repository. | Install the package next to the config (the generator package itself, for defineConfig), or use a .json config. |
Cannot load ... : the module 'esbuild' is not installed. | The transpiler the .ts loader needs is missing from node_modules. | Reinstall dependencies; esbuild is installed with the generator. |
Direct mode requires --input, --output, and --output-types. | openapi-to-k6 was given one or two of the three direct-mode flags. | Pass all three, or use a configuration file. See Command-line reference. |
The configuration file format, including where defaults may and may not be used, is described in Configuration files.
Specification
Errors in this phase fail the spec they belong to; other specs in the same run still generate, and the run exits with code 1. Warnings do not fail anything and are printed in a block after the spec, prefixed with the package name.
| Symptom | Cause | Fix |
|---|---|---|
Input file not found: specs/api.yaml | input is resolved from the current directory, not from the config file. | Run from the directory the path was written for, or make the path match. |
Empty or invalid OpenAPI specification in specs/api.yaml | The file is blank, or parses to a scalar rather than a document. | Point input at the real specification. |
No schemas found in OpenAPI spec | The document has no components.schemas. Every generator, the k6 and Playwright ones included, needs at least one component schema, even when the operations describe their shapes inline. | Move at least the shared shapes into components.schemas and reference them with $ref. |
Warning All 8 operations were filtered out. Check your operationFilters configuration., and no client or service file is written | The operationFilters removed every operation. A frequent cause with stripPathPrefix: the Playwright and k6 generators match includePaths/excludePaths against the path after the prefix is stripped, while the TypeScript and Zod generators match the original path, so a filter written for one form matches nothing in the other. | Write the path patterns for the form that generator matches, and check tags and methods against the specification; see Operation filters. |
Invalid OpenAPI specification: missing 'openapi' or 'swagger' field in specs/common.yaml | The file is a bare collection of schemas, not an OpenAPI document. | Give it an openapi: 3.0.3 header and an info block, or reference its schemas from a real specification with an external $ref. |
Failed to parse OpenAPI specification from: specs/api.yaml followed by a YAML or JSON error | Syntax error in the file; the YAML parser's message gives the line and column. | Fix the syntax. |
Invalid schema 'User': Invalid reference at 'profile': '#/components/schemas/NonExistentProfile' points to non-existent schema 'NonExistentProfile' | A $ref names a schema that does not exist in the document. | Correct the name, or add the schema. If the target lives in another file, write the file path in the $ref (./common.yaml#/components/schemas/Profile). |
Remote reference "https://schemas.acme.com/v2/money.yaml" cannot be resolved. followed by Remote documents are never fetched during generation. Map the URL to a local file: and a suggested refMappings block | The specification references a schema registry by URL. Generation never downloads documents. | Put a copy of the document in your repository and add the suggested refMappings entry; see Specs and references. |
Referenced file not found: /home/me/project/specs/common.yaml with Referenced from: /home/me/project/specs/api.yaml | An external $ref is resolved relative to the document that contains it, and no file exists there. | Fix the relative path in the $ref, or for a mapped remote URL check the mapping's directory, which is relative to the working directory. |
Warning Reference "./common.yaml#/Money" does not point at a component and cannot be inlined; only #/components/<type>/<name> and #/definitions/<name> are supported. | The pointer part of an external reference does not target a component. | Reference #/components/schemas/Money (or #/definitions/Money in a Swagger 2.0 file). |
Warning Reference "./common.yaml#/components/schemas/Money" does not resolve in that document. | The file exists but has no such component. | Check the name in the referenced file. |
Warning "Money" from ./common.yaml collides with a name already in this spec; it was inlined as "CommonMoney". | Your specification already declares a schema with the external target's name. | Nothing is wrong; rename one of the two if you want the shorter name. |
Warning Name collision: "schema "Pet_Kind"" and "schema "pet-kind"" both generate "petKindSchema". The generated file will declare it twice - rename one, or use prefix/suffix to separate them. | Two schemas (or two operations) normalise to one identifier. The generated file then declares the name twice and does not compile; in Zod the second declaration would shadow the first. | Rename one schema in the specification, or separate them with prefix/suffix; see Naming. |
Warning Specification declares 3 webhook(s) but no paths. Webhooks are not currently generated, so no output will be produced for them. | An OpenAPI 3.1 document with only webhooks. | Nothing to fix; webhooks are not supported. See OpenAPI feature support. |
Warning An if/then/else condition uses keywords the generator cannot express (only a property's type, const, minimum and maximum, plus required, are supported). The conditional was skipped; validate this constraint yourself. | The if uses a keyword outside that set. | Rewrite the condition with the supported keywords, or add the check in your own code. |
Warning Pattern "[" is not a valid regular expression and has been dropped: ... | A pattern is not a valid JavaScript regular expression. | Fix the pattern; the generated code uses JavaScript regular expression syntax. |
Refusing to load more than 100 referenced documents - the spec may reference itself in a loop | An unusually large or self-referencing graph of external documents. | Check the references between files. |
Generated output
| Symptom | Cause | Fix |
|---|---|---|
TypeScript reports Duplicate identifier 'petKindSchema' or Cannot redeclare block-scoped variable in a generated file | A name collision; the run printed the warning above. | Rename one of the colliding schemas or operations, or use prefix/suffix. |
Two generators name the same operation differently (GetUserByIdQueryParams in the types, getUsersByUserId in the client) | useOperationId defaults to true for the TypeScript and Zod generators and to false for the Playwright and k6 generators. | Set useOperationId explicitly, in defaults, in every config that must agree; see Naming. |
Type instantiation is excessively deep and possibly infinite (TS2589) when compiling generated Zod schemas | Very large or deeply nested schemas with z.infer<typeof schema>. | Set outputZodSchemas so types and schemas go to separate files with satisfies z.ZodType<T>; if that is not enough, raise typeAssertionThreshold (Zod options). |
A schema generated by 1.0.0 throws ReferenceError: Cannot access 'baseSchema' before initialization when imported | A schema reached through an alias was declared before the schema it extends. | Regenerate with 2.0.0, which orders aliases correctly. |
| A Playwright service generated by 1.0.0 does not compile for a path with trailing whitespace in its key | The method name kept the space. | Regenerate with 2.0.0. |
| Parsing an object without a property now returns the property with a value | The property declares a default, which 2.0.0 honours as .default(value). | Expected; remove the default from the specification if the key must stay absent. |
An object the API returns fails with Unrecognized key: "x" | mode defaults to strict, so a property the specification does not describe is rejected. Usually the specification is out of date. | Document the property, or set mode: "normal" (or per direction with response.mode) to accept undocumented keys. |
The client sends ?tags=a&tags=b where 1.0.0 sent ?tags=a,b | 2.0.0 follows the OpenAPI default, style: form with explode: true. | Declare style: form and explode: false on the parameter if the server expects the comma form. |
stripPathPrefix: "/api" no longer shortens /apikeys/{id} | A prefix now has to end at a segment boundary. | Intended; /api matches /api/... only. |
Schemas lost their z.lazy() wrapper or moved in the file after upgrading | Only schemas that are actually on a reference cycle are treated as circular in 2.0.0. | Nothing to fix; the output compiles the same. |
Licence errors
A failed licence check exits with code 1 before anything is written and prints one line of the form License check failed (CODE). <what to do> Contact Cerios - Spartaficial to obtain or renew a license. The codes fall into four families; Licensing has the full table and the setup instructions.
| Code family | Cause | Fix |
|---|---|---|
LICENSE_KEY_MISSING | SPARTAFICIAL_LICENSE_KEY is not set in the environment the generator runs in. | Set the variable; in CI, as a secret. |
INVALID_FORMAT, INVALID_HEADER, INVALID_PAYLOAD, INVALID_SIGNATURE, ISSUER_MISMATCH, UNKNOWN_KEY_ID | The value is not the key as issued: truncated, altered, or from another issuer or an older build. | Re-copy the key in full; if it still fails, upgrade the package or request a fresh key. |
EXPIRED, NOT_YET_VALID | The key's validity window does not include today. | Renew the key, or check the system clock. |
PACKAGE_NAME_MISMATCH, PACKAGE_JSON_INVALID, LICENSE_CONFIG_INVALID | The key is restricted to one project and the generator was run against another package.json. | Run from the project the key names; in k6 direct mode the message says which directory was read. |
One message carries no code: This build was published without a signing key, so licenses cannot be verified. This is a packaging fault, not a problem with your license. Nothing on your side fixes it; report it.
Run time
These appear when the generated code is compiled, bundled or executed, not during generation. Runtime entry points explains the two ./runtime modules the clients import.
k6
| Symptom | Cause | Fix |
|---|---|---|
k6 run fails with The moduleSpecifier "@spartaficial/openapi-to-k6/runtime" couldn't be found on local disk | k6 does not read package.json exports, so it cannot resolve the runtime import in the generated client. | Bundle the script with esbuild, webpack or rollup before k6 run; see k6 generator. |
result.ok is false and result.data is a string for an endpoint that used to parse | The service reads the body as the declared content type says; a text/plain response is returned as text instead of being passed to JSON.parse. | Expected; check result.response.status and result.data. |
| A form or multipart request arrives at the server as a JSON string | The body was serialised by hand before calling the client. | Pass the plain object; the client hands form and multipart bodies to k6 unchanged. |
Zod
| Symptom | Cause | Fix |
|---|---|---|
Importing a generated file throws TypeError: z.uuid is not a function, Cannot read properties of undefined (reading 'datetime') or z.prettifyError is not a function | Zod 3 is installed, or two copies of Zod are and the generated code resolves the older one. The generated code uses Zod 4 APIs (z.uuid(), z.iso.datetime(), z.strictObject()). | Install zod@^4 and check npm ls zod shows one version. See Requirements. |
z.strictObject(...).extend is not a function or similar on a recent Zod | A Zod 4 pre-release or a custom build. | Use a released 4.x. |
Playwright
| Symptom | Cause | Fix |
|---|---|---|
Cannot find module '@spartaficial/openapi-to-zod-playwright/runtime' when running tests | The generated service imports the package's runtime helpers; the package is not installed where the tests run. | Add @spartaficial/openapi-to-zod-playwright as a dev dependency of the project that runs the tests. |
A service method fails with expect(received).toBe(expected) and the response body as the message | The service asserts the status code documented for that method; the API answered with another status. | Use the client (which asserts nothing) for negative tests, or generate methods for error responses with includeStatusCodes; see Playwright generator. |
A service method throws ZodValidationError with ✖ lines | The response (or, with validateServiceRequest: true, the request body) does not match the schema. The API deviates from its specification, or the specification is out of date. | Fix whichever is wrong; the message names the path and, by default, the value received. |
error.issues is undefined in a catch | zodErrorFormat is prettify or prettifyWithValues, which throw ZodValidationError, not a raw ZodError. | Read error.zodError.issues (or error.issues, which ZodValidationError also exposes), or set zodErrorFormat: "standard". |
zodErrorFormat decides what a failed validation looks like. For a User schema with id: z.uuid(), email: z.email() and strict keys, the same wrong body produces three different errors:
--- zodErrorFormat: "prettifyWithValues" (default)
ZodValidationError:
✖ Invalid input: expected string, received number
→ at id
✖ Invalid email address (received: "not-an-email")
→ at email
✖ Unrecognized key: "extra"
→ at
--- zodErrorFormat: "prettify"
ZodValidationError: ✖ Unrecognized key: "extra"
✖ Invalid input: expected string, received number
→ at id
✖ Invalid email address
→ at email
--- zodErrorFormat: "standard"
ZodError with 3 issues, for example:
{ "code": "invalid_type", "expected": "string", "path": ["id"], "message": "Invalid input: expected string, received number" }
The prettifyWithValues form appends the value that was received wherever it is a primitive; the prettify form is Zod's own prettifyError output; the standard form is the untouched ZodError, which is the right choice when a test inspects issues itself. The option is described in Playwright options.