Official codex-cli 0.120.0 sends raw multibyte JSON in x-codex-turn-metadata, breaking HTTP interoperability
What version of Codex CLI is running?
codex-cli 0.120.0
What subscription do you have?
ChatGPT Plus
Which model were you using?
gpt-5.1-codex-mini
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What terminal emulator and version are you using (if applicable)?
PowerShell 7.6.0
What issue are you seeing?
x-codex-turn-metadata is emitted by the official CLI as raw JSON rather than an ASCII-safe encoding. When that metadata
contains non-ASCII characters, this breaks HTTP interoperability.
I gathered three independent repros:
- Standard client stack repro:
Python urllib.request fails before send with:
UnicodeEncodeError: 'latin-1' codec can't encode characters...
when the same logical turn metadata JSON is placed directly in x-codex-turn-metadata.
- Hosted API repro:
Node fetch against Azure OpenAI fails before send for the raw header with:
TypeError: Cannot convert argument to a ByteString because the character at index 31 has a value of 26481 which is
greater than 255.
The same logical metadata succeeds when Base64-encoded. Against:
GET https://example-resource.openai.azure.com/openai/v1/models
the Base64 version returned 200 OK.
- Official CLI repro:
I ran the official npm-installed codex-cli 0.120.0 from a Git repo whose absolute path contains Japanese characters:
C:\Users\<redacted>\AppData\Local\Temp\codex-turn-meta-repro-東京\repo
and pointed it at a local mock /v1/responses endpoint.
The mock server captured this request header:
{
"path": "/v1/responses",
"turn_metadata": "{\"session_id\":\"019d...\",\"turn_id\":\"019d...\",\"workspaces\":{\"C:\\\\Users\\\\<redacted>\\\\AppData\
\\\Local\\\\Temp\\\\codex-turn-meta-repro-\u00e6\^]\u00b1\u00e4\u00ba\u00ac\\\\repo\":{\"latest_git_commit_hash\":
\"ab1e986b4d8d86bdf5b69f6c614e8840789b6457\",\"has_changes\":false}},\"sandbox\":\"none\"}"
}
That value is not Base64. It is raw JSON placed directly in the header, and the Japanese path appears as mojibake bytes
in the captured header value instead of being transport-safe.
I also compared the official CLI with a locally built binary from my fork of Codex:
- repo: https://github.com/amabile4/codex
- branch: azure/release-0.120.0
That fork only changes the wire encoding of x-codex-turn-metadata from raw JSON to Base64. It does not change the
logical metadata payload.
Under the same machine / same repo / same prompt / same local mock server:
- the official codex-cli 0.120.0 sends raw JSON in x-codex-turn-metadata
- the fork build sends Base64 in x-codex-turn-metadata
The mock server decodes the fork header back to the same logical JSON, including the original Japanese workspace path.
So the fork is not changing the meaning of the metadata, only making the transport encoding safe.
What steps can reproduce the bug?
- Confirm the official CLI version:
codex --version
- Create a Git repo whose absolute path contains non-ASCII characters, for example Japanese:
$root = Join-Path $env:TEMP 'codex-turn-meta-repro-東京'
$repo = Join-Path $root 'repo'
New-Item -ItemType Directory -Force -Path $repo | Out-Null
Set-Location $repo
git init
Set-Content README.md 'repro'
git add README.md
git -c user.name='repro' -c user.email='repro@example.com' commit -m 'init'
- Start a local mock HTTP server that logs request headers for /v1/responses.
- Run the official CLI against that local mock provider:
codex exec --json `
-C $repo `
-c model_provider='mock' `
-c 'model_providers.mock.name="Mock"' `
-c 'model_providers.mock.base_url="http://127.0.0.1:8012/v1"' `
-c 'model_providers.mock.wire_api="responses"' `
-m 'gpt-5.1-codex-mini' `
'Reply with exactly OK. Do not use any tools.'
- Inspect the mock server log. The official CLI sends raw JSON in x-codex-turn-metadata, including the non-ASCII
workspace path.
- As an interoperability check, send the same logical metadata using a minimal repro client:
- raw JSON in x-codex-turn-metadata
- Base64-encoded JSON in x-codex-turn-metadata
- Observe:
- raw fails in standard client stacks
- Base64 succeeds
- Optional A/B confirmation:
run a locally built binary from amabile4/codex branch azure/release-0.120.0, where the only relevant change is Base64
encoding of x-codex-turn-metadata. Under the same repo and same mock server, the fork build sends Base64 while the
official CLI sends raw JSON.
What is the expected behavior?
x-codex-turn-metadata should be encoded in an ASCII-safe form before it is placed on the wire.
A Base64-encoded JSON blob is sufficient. The official CLI should not emit raw multibyte JSON header values that can:
- fail in standard HTTP clients before the request is sent
- break reconnect or request handling on some platforms
- fail against providers or gateways that enforce ASCII-safe header handling
Additional information
- Confirmed examples currently gathered:
- Python urllib.request: raw fails, Base64 succeeds
- Node fetch -> Azure OpenAI GET /openai/v1/models: raw fails before send, Base64 succeeds with 200 OK
- Official codex-cli 0.120.0 -> local mock /v1/responses: raw JSON is actually emitted in x-codex-turn-metadata
- Local fork build from amabile4/codex branch azure/release-0.120.0 -> local mock /v1/responses: Base64 is emitted
instead and decodes cleanly back to the same JSON
- This is not only an Azure-specific complaint. Azure is one impacted environment, but the underlying bug is that the
header value is not transport-safe across multiple HTTP stacks.
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Did this problem occur with previous versions? If you downgrade to 0.119.0, can you repro it? I'm trying to determine whether this was a recent regression.
I have not tested v0.119.0 specifically.
However, I was able to reproduce the same issue on v0.116.0, v0.117.0, v0.118.0, and v0.120.0 over the past few weeks,
so this does not appear to be a recent regression introduced in v0.120.0.
I could not check v0.119.0 because v0.120.0 replaced it shortly after release.
OK, thanks. Sounds like this isn't a regression then.
Additional repro: Chinese workspace path on macOS — codex-cli 0.125.0-alpha.3
Same root cause, different script. Workspace path with Chinese characters triggers identical header-encoding failure on every reconnect attempt.
Environment:
Repro path:
Error (5/5 reconnects fail identically):
The raw UTF-8 bytes
\xe7\xad\x96\xe7\x95\xa5(策略) are placed directly in the header value, causing the HTTP client to reject it on every reconnect. Since the session workspace path doesn't change between attempts, all 5 retries fail deterministically.Workaround we deployed (for anyone hitting this in production):
We create an ASCII-only symlink alias under
/tmp/clowder-codex-workspaces/workspace-<sha256-prefix>pointing to the real workspace, and pass the alias path ascwdto the Codex CLI. The CLI then puts the ASCII alias path in the header instead of the original Chinese path. Files still read/write to the real directory through the symlink.This confirms the issue persists in 0.125.0-alpha.3 and affects Chinese paths (not just Japanese), so it's a general non-ASCII problem as originally reported.
I can confirm a similar repro on a newer CLI version.
Sanitized environment/details:
codex-cli 0.124.0D:\...\ascii_parent\毕设Observed behavior during a longer task:
The failing header value included the workspace key with the Chinese directory represented as raw UTF-8 bytes in the diagnostic output:
Those bytes decode to
毕设, the final segment of the workspace path.This does not look like ordinary proxy/network instability from the client-side symptom. The generic stream disconnect is followed by a very specific header conversion failure for
x-codex-turn-metadata. In practice, repeated reconnect attempts can fail because they keep sending the same metadata header. Sometimes a later reconnect/session resumes, likely because a different reconnect/request path or gateway node does not hit the same strict header conversion path, but the underlying trigger remains the non-ASCII workspace path in turn metadata.The fix direction in #19620, escaping turn metadata as ASCII-safe JSON before putting it in the header, matches this repro.
Thanks for the bug report. This will be addressed in the next release.