Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Codex turns fail with a misleading capacity error when the workspace path contains CJK characters (header 'x-codex-turn-metadata' has invalid value)

Open
#8,050 1 comment 1 reaction 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
api

Research direction

Read src/codex/forward-transport-headers.ts around the failing Headers.set call and review draft PR #8040, which the issue says addresses the same root cause. Check whether its regression coverage includes a CJK workspace path; done means turn metadata can be serialised in the header and its values survive parsing, without the misleading capacity failure.

Written by the indexing model from the issue text.

Description

bug
Client or integration

Codex App (desktop, macOS), Codex CLI 0.166.0-alpha.5.1, installed @bitkyc08/opencodex 2.95.0 with the built-in OpenAI provider pointed at the local proxy (127.0.0.1:10100).

Area

Proxy and routing, specifically the account-pool path that forwards Codex turn metadata.

Summary

Every turn in one project failed after the proxy rejected the request with a vague capacity message, so the cause was invisible from the client: the workspace path contained CJK characters, the path was embedded verbatim in x-codex-turn-metadata, and Headers.set refused it.

  • In /Users/<user>/Documents/示例目录/example-project (a git working tree whose absolute path contains 示例目录), every single turn failed. Codex retried 5/5, then showed We’re currently experiencing high demand, which may cause temporary errors. Four separate threads were opened over 25 minutes and all four failed the same way.
  • In a projectless Codex chat whose directory is pure ASCII (/Users/<user>/Documents/ascii-chat), the same model answered normally.

The workspace path is only attached to request_kind: "turn" requests, so prewarm succeeded and the client looked healthy right up to the first real question. The failure is therefore not upstream capacity, and the retry loop sends the identical invalid header five times before giving up.

Grepping ~/.codex/logs_2.sqlite for the four failed threads shows the cwd is the CJK directory in all four, and the rendered client error is exactly the capacity string above, which is why this took a long time to attribute.

Reproduction
  1. Put a git repository under a directory whose absolute path contains non-ASCII characters, for example /Users/<user>/Documents/示例目录/example-project (git status clean or dirty, either way).
  2. Configure Codex to use the proxy, then open that directory as the workspace and send any message, e.g. codex exec "只回复两个字:你好".
  3. Observe that the turn never produces output. The client retries and ends with:
stream disconnected - retrying sampling request (5/5 in 3.34s)... sampling_error=We’re currently experiencing high demand, which may cause temporary errors.
ERROR: We’re currently experiencing high demand, which may cause temporary errors.
  1. The proxy log (~/.opencodex/service.log) shows the actual cause, once per attempt, with the source line at src/codex/forward-transport-headers.ts:65:
60 |   if (installId && installId.trim()) {
61 |     headers.set(CODEX_INSTALLATION_ID_HEADER, deriveCodexAccountInstallationId(chatgptAccountId, installId));
62 |   }
63 |   const turnMeta = headers.get(CODEX_TURN_METADATA_HEADER);
64 |   if (turnMeta) {
65 |     headers.set(CODEX_TURN_METADATA_HEADER, rewriteTurnMetadataInstallationId(turnMeta, chatgptAccountId));
                 ^
TypeError: Header 'x-codex-turn-metadata' has invalid value
POST - http://127.0.0.1:10100/v1/responses failed
  1. Repeat the same prompt from a directory with an ASCII-only path; it succeeds on the first attempt with no retries.

Capturing the real outbound bytes on a local listener shows the header the client sends for a CJK workspace (path abbreviated):

{"installation_id":"…","request_kind":"turn","workspaces":{"/Users/<user>/Documents/示例目录/example-project":{"latest_git_commit_hash":"…","has_changes":true}},"model":"a6-ds/deepseek-v4.1-flash-1017"}

A minimal, dependency-free reproducer of the failing line — rewriteTurnMetadataInstallationId re-serialises the parsed record, so the CJK path is decoded back to literal characters, and the subsequent Headers.set rejects any code unit above U+00FF:

const meta = JSON.stringify({ installation_id: "abc", workspaces: { "/tmp/中文/项目": {} } });
const rewritten = JSON.stringify({ ...JSON.parse(meta), installation_id: "xyz" });
new Headers({ "x-codex-turn-metadata": rewritten }); // TypeError: Header 'x-codex-turn-metadata' has invalid value
Expected behavior

A workspace path containing CJK characters must work exactly like an ASCII path: the turn reaches the provider, and the metadata round-trips with its values intact. Two supporting expectations:

  • Header serialisation should be ASCII-safe, which is what PR #8040 already does for the parsed-record path.
  • If a header still cannot be serialised, the failure should surface as an actionable error naming the header and the offending value rather than being reported to the client as upstream capacity, since that message invites five pointless retries and sends users looking at their provider quota.
Version

@bitkyc08/opencodex 2.95.0. Client: Codex App / Codex CLI 0.166.0-alpha.5.1.

Operating system

macOS 26.7.1 (build 25G241), Apple silicon, bundled Bun 1.4.4.

Logs or error output

Proxy log, repeating for every attempt (~/.opencodex/service.log):

TypeError: Header 'x-codex-turn-metadata' has invalid value
      at isolateCodexPoolAccountHeaders (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/codex/forward-transport-headers.ts:65:13)
      at materializeCodexUpstreamAuth (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/codex/auth-context.ts:1850:5)
      at resolveFirstUsableOpenAiSidecar (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/providers/openai-sidecar.ts:253:25)
      at async prepareResponsesSidecarAuth (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/server/responses/request-sidecar-auth.ts:94:29)
      at async <anonymous> (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/server/responses/core-pipeline.ts:56:34)
      at async handleResponsesInner (<npm-prefix>/lib/node_modules/@bitkyc08/opencodex/src/server/responses/core-pipeline.ts:126:7)
POST - http://127.0.0.1:10100/v1/responses failed

Count of that header error in my log after one afternoon of use: 483, all from the one CJK project.

Client side, the turn status recorded for the four failed threads is failed with We’re currently experiencing high demand, which may cause temporary errors. and 27s, 9s, 23s, 27s durations respectively — i.e. the full retry budget each time.

Screenshots and supporting files

No screenshots; the defect is fully described by the request path, the proxy stack trace, and the captured header above. I can attach a redacted proxy log excerpt if that helps.

Redacted configuration

Default single-account pool on the local machine, no custom routing:

{
  "model": "a6-ds/deepseek-v4.1-flash-1017",
  "openai_base_url": "http://127.0.0.1:10100/v1",
  "codexAccounts": [{ "id": "chatgpt-…", "plan": "plus", "isMain": false }],
  "activeCodexAccountId": "chatgpt-…",
  "pausedCodexAccountIds": ["__main__"]
}
Additional context

A local workaround on 2.95.0 that has held up over repeated real turns: escape every code unit above U+00FF to \uXXXX immediately before writing the header. For a CJK path this reproduces the reported symptom before the change (TypeError: Header 'x-codex-turn-metadata' has invalid value) and passes after it, with the path string comparing equal after JSON.parse:

function toHeaderSafeJson(value: string): string {
  let out = "";
  for (const ch of value) {
    const code = ch.codePointAt(0)!;
    if (code <= 0xff) { out += ch; continue; }
    const units = code <= 0xffff ? [code] : [0xd800 + ((code - 0x10000) >> 10), 0xdc00 + ((code - 0x10000) & 0x3ff)];
    for (const unit of units) out += String.fromCharCode(92) + "u" + unit.toString(16).padStart(4, "0");
  }
  return out;
}

Two notes for whoever picks this up:

  • This is the same root cause as PR #8040, which is still a draft and whose regression test covers Korean and emoji via JSON.parse/re-serialise. A CJK workspace path exercises the same branch, so the existing fix likely resolves this report too; I am filing it because the searchable symptom here (the capacity message) is what users actually see, and because #8042 references the PR but no issue documented the CJK case.
  • Worth keeping in mind for coverage: the client-side error mapping is the reason this is expensive to diagnose. Turning an unrepresentable header into a capacity message is indistinguishable from real throttling.
Checks
  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.
Dominant language
TypeScript
Stars
16.9k
Forks
1.3k
Avg merge
16h 42m
Merged PRs (30d)
695

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lidge-jun/opencodex

All issues in lidge-jun/opencodex

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.