{"schema_version":"1.0","publisher":"Primitive SDKs","canonical_url":"https://test.abhinandan.one/codegen-troubleshooting","markdown_url":"https://test.abhinandan.one/codegen-troubleshooting.md","article":{"id":"111c854f-98bd-4fbd-9eef-b469df9251d0","article_slug":"codegen-troubleshooting","parent_article_slug":null,"parent_article_title":null,"kind":"troubleshooting","published_at":"2026-08-11T18:55:08.7777+00:00","keywords":["fix-generated-api-imports.ts","MemoryJsonValue","Unable to repair generated MemoryJsonValue type","guardOptionalBodyContentType","generate_api_client.py","openapi-python-client"],"meta_description":"Fixing codegen regeneration errors involves rerunning generate-openapi-artifacts.ts, fix-generated-api-imports.ts, or the Python generate_api_client.py fixup pass.","og_image_url":null,"source_file_paths":["packages/api-core/scripts/fix-generated-api-imports.ts","sdk-python/scripts/generate_api_client.py"],"recording_id":null,"replayable":false,"task_name":"Codegen Troubleshooting","category":"Troubleshooting","summary":null,"description":"Diagnoses the three regeneration failures that break generated SDK clients: schema drift in MemoryJsonValue, stale imports missing.js extensions, and mismatched Content-Type headers on optional-body requests.","content_kind":"repo_page","content_markdown":"Both the Node client in [api-core](api-core-overview) and the Python client under `primitive.api` run a post-generation fixup script that repairs known generator output problems. When a generator version bump changes that output, the fixup either throws or stops matching, and this page lists the failures you'll see.\n\nFor the end-to-end regeneration command sequence, see [Regenerating SDK Code from the OpenAPI Spec](codegen-workflow). For how the pipeline fits together, see [Architecture: Shared Codegen Pipeline](codegen-architecture).\n\n## Unable to repair generated MemoryJsonValue type\n\n`fixMemoryJsonValueType` in `packages/api-core/scripts/fix-generated-api-imports.ts` throws this when its regex no longer matches the generated `MemoryJsonValue` alias:\n\n```text\nUnable to repair generated MemoryJsonValue type in <file>. The codegen output shape changed; update fixMemoryJsonValueType before publishing.\n```\n\n**Cause**: `@hey-api/openapi-ts` treats the OpenAPI 3.1 `type: \"null\"` branch of this recursive JSON schema as `unknown`, which widens the whole generated alias, so the fixup script patches the alias back to the exact JSON type (see [Generated TypeScript Client Fixups](typescript-client-fixups) for the full explanation of this repair). It matches the generated block with a regex replacement:\n\n```typescript\n// packages/api-core/scripts/fix-generated-api-imports.ts\nconst MEMORY_JSON_VALUE_PATTERN =\n  /export type MemoryJsonValue = [\\s\\S]*?;\\n\\n\\/\\*\\*\\n \\* Memory scope\\./;\n```\n\nThat pattern anchors on the literal text immediately following the generated type, including the `* Memory scope.` docstring on the next exported symbol. If the OpenAPI spec's schema ordering changes, or `@hey-api/openapi-ts` changes its comment or type-emission format, the pattern no longer matches and the script throws rather than silently leaving the `unknown`-widened type in place.\n\n**Fix**: open the newly generated file (under `packages/api-core/src/api/`) and check what `export type MemoryJsonValue = ...` and the symbol that follows it actually look like now. Update `MEMORY_JSON_VALUE_PATTERN` and `MEMORY_JSON_VALUE_TYPE` in `fix-generated-api-imports.ts` to match the new shape, then re-run:\n\n```bash\ncd packages/api-core\npnpm generate:api\n```\n\nConfirm the fix by grepping the output for the exact type:\n\n```bash\n# from packages/api-core\ngrep -rA3 \"export type MemoryJsonValue\" src/api\n```\n\nYou should see the null-inclusive union `string | number | boolean | Array<MemoryJsonValue> | { [key: string]: MemoryJsonValue } | null`, not `unknown`. See [Memory Value Validation Helper](memory-json-value-helper) for how `isMemoryJsonValue` depends on this type staying accurate.\n\n## Generated imports missing `.js` extensions\n\nRelative imports in the generated TypeScript need a `.js` extension for Node ESM resolution, and `@hey-api/openapi-ts` emits them without one, so unresolvable-module errors mean the fixup pass did not run.\n\n**Cause**: the generator emits relative specifiers such as `from \"./types\"`, and `fix-generated-api-imports.ts` rewrites them to add `.js` (or `/index.js` for directory imports), as described in [Generated TypeScript Client Fixups](typescript-client-fixups):\n\n```typescript\n// packages/api-core/scripts/fix-generated-api-imports.ts\nfunction addJsExtension(file: string, specifier: string): string {\n  if (!specifier.startsWith(\"./\") && !specifier.startsWith(\"../\")) {\n    return specifier;\n  }\n  if (specifier.endsWith(\".js\") || specifier.endsWith(\".json\")) {\n    return specifier;\n  }\n  // ...resolves whether the target is a directory (adds /index.js)\n  // or a file (adds .js)\n}\n```\n\n**Fix**: this step runs automatically as part of `pnpm generate:api` (which calls `openapi-ts` then `tsx scripts/fix-generated-api-imports.ts`). If you see unfixed imports, you likely ran the raw `openapi-ts` generator directly and skipped the fixup script. Re-run the full sequence:\n\n```bash\ncd packages/api-core\npnpm generate:api\n```\n\nNever hand-edit import paths in generated files, the next regeneration overwrites them.\n\n## Optional-body request sends `Content-Type: application/json` with no body\n\nThe generator adds the JSON `Content-Type` header to every operation that declares a request body, so optional-body operations send the header even when the caller omits the payload, which is wrong on the wire.\n\n**Cause**: `@hey-api/openapi-ts` unconditionally emits:\n\n```typescript\n// generated operation, before the fixup\nheaders: { 'Content-Type': 'application/json', ...options.headers }\n```\n\non every operation whose OpenAPI schema declares a request body, regardless of whether that body is *required*. The optional-body operations affected are `testFunction`, `cli_logout`, `start_cli_login`, and `search_emails`. `fix-generated-api-imports.ts` guards this with `guardOptionalBodyContentType`, which rewrites the header assignment to fire only when a body is actually present (see [Generated TypeScript Client Fixups](typescript-client-fixups)):\n\n```typescript\n// packages/api-core/scripts/fix-generated-api-imports.ts\nfunction guardOptionalBodyContentType(content: string): string {\n  return content.replace(\n    /(headers:\\s*\\{\\n\\s*)'Content-Type':\\s*'application\\/json',\\n(\\s*\\.\\.\\.options\\.headers\\n\\s*\\})/g,\n    \"$1...(options.body !== undefined && { 'Content-Type': 'application/json' }),\\n$2\",\n  );\n}\n```\n\nRequired-body operations are unaffected: the type system guarantees `body` is always defined for those, so the header still ships in practice.\n\n**Fix**: this transform runs automatically inside `fix-generated-api-imports.ts`. If a generated operation still emits the unconditional header:\n\n1. Confirm you ran `pnpm generate:api` (not the raw `openapi-ts` command alone).\n2. Check whether the operation's shape in the generated source still matches the regex, `@hey-api/openapi-ts` version bumps can reformat the emitted `headers: {...}` block (different whitespace, reordered keys) and silently break the match. Diff the generated file's `headers:` block against the pattern and update the regex in `guardOptionalBodyContentType` if the format changed.\n3. Re-run generation and grep for the guarded form:\n\n```bash\n# from packages/api-core\ngrep -rA2 \"'Content-Type'\" src/api\n```\n\nYou should see `...(options.body !== undefined && { 'Content-Type': 'application/json' })`, not a bare `'Content-Type': 'application/json',`.\n\nThe Python client has the analogous problem and fix in `sdk-python/scripts/generate_api_client.py`'s `guard_optional_body_content_type`, which re-indents the same unconditional header assignment so it only fires inside the `if not isinstance(body, Unset):` block. If you hit the Python equivalent, re-run:\n\n```bash\ncd sdk-python\nuv run python scripts/generate_api_client.py\n```\n\nand confirm with:\n\n```bash\n# from sdk-python\ngrep -rB2 'headers\\[\"Content-Type\"\\] = \"application/json\"' src/primitive/api/api\n```\n\nThe line should be indented inside the `if not isinstance(body, Unset):` block, not at the function's top level.\n\n## Duplicate imports in the generated Python client\n\n`openapi-python-client` 0.28.3 occasionally emits the same import line twice, so strict linters such as ruff and basedpyright flag repeated `from ... import ...` lines in generated model files.\n\n**Cause**: the duplication shows up most often as `from ..types import UNSET, Unset` in 201-response models. It is semantically a no-op but trips downstream strict linters.\n\n**Fix**: `generate_api_client.py`'s `dedupe_imports` runs automatically after generation and strips repeated module-level import lines (it only matches unindented lines, so imports inside `TYPE_CHECKING` blocks or function bodies are left alone). If you still see duplicates after generating, confirm you ran the wrapper script rather than calling `openapi-python-client generate` directly:\n\n```bash\ncd sdk-python\nuv run python scripts/generate_api_client.py\n```\n\n## File payload responses wrap `response.text` instead of `response.content`\n\nGenerated Python file-download responses wrap the response in `BytesIO`, which requires `bytes`, so `openapi-python-client`'s `BytesIO(response.text)` output has to be rewritten.\n\n**Fix**: `use_bytes_for_file_responses` in `sdk-python/scripts/generate_api_client.py` rewrites `BytesIO(response.text)` to `BytesIO(response.content)` automatically, as part of the same `generate_api_client.py` invocation above. There is no separate command to run.\n\n## Not sure which fixup is out of sync\n\nRegenerate everything from the OpenAPI source of truth rather than patching generated files by hand:\n\n```bash\nmake node-generate python-generate go-generate\n```\n\n<Warning>\n\nNever hand-edit files under `packages/api-core/src/api/` or `sdk-python/src/primitive/api/`. Any manual fix is silently overwritten the next time someone runs the generator. Fix the *script* that produces the file, not the file itself.\n\n</Warning>\n\nAfter regenerating, run each SDK's checks to catch anything the fixups missed:\n\n```bash\nmake node-check python-check go-check\n```","canonical_base_url":"https://test.abhinandan.one","seo_indexing_enabled":true,"last_modified":"2026-08-21T18:22:43.359885+00:00","video_url":null,"voiceover_url":null,"tools_used":[],"demonstrated_by":[],"steps":[],"related_links":[],"intro":null,"prerequisites":[],"verification":[],"troubleshooting":[],"suggest_edit_url":"https://github.com/abhi-browzer/primitive-sdks/edit/main/packages/api-core/scripts/fix-generated-api-imports.ts","raise_issue_url":"https://github.com/abhi-browzer/primitive-sdks/issues/new?title=Docs+feedback%3A+Codegen+Troubleshooting&body=Page%3A+https%3A%2F%2Ftest.abhinandan.one%2Fcodegen-troubleshooting","page_feedback_enabled":true,"verified_ref":null,"verified_at":"2026-08-11T18:38:45.205849+00:00"}}