Client or integration
Codex App. Codex runtime codex-cli 0.155.0-alpha.2.6 (shipped with ChatGPT.app, installed 2026-09-17 10:03, previously 0.154.0-alpha.6.2). Also reproduced with minimal direct HTTP requests against the proxy and against the upstream.
Provider or upstream service
OpenCode Go (OpenCode-Go, https://opencode.ai/zen/go/v1) — the gateway that identifies itself as "Console Go" in the error message. Affects muse-spark-1.3-contributor and muse-spark-1.2-contributor; the same request shape succeeds on other models behind the same base URL.
OpenCodex version
2.57.0 (installed CLI, latest on npm at the time of writing). macOS, Apple Silicon. Observed 2026-09-17.
Endpoint or capability
Inbound POST /v1/responses on the proxy → outbound Responses passthrough to /zen/go/v1/responses (adapter: openai-responses, OpenCode-Go provider). Request body shape / unknown-parameter handling.
Current behaviour
Every routed turn to muse-spark-1.3-contributor fails with HTTP 400:
Error from provider (Console Go): Upstream request failed: [invalid_request_error] unknown parameter `access_programs`
Root cause: Codex 0.155 attaches a new OpenAI-private top-level field, access_programs, to its Responses request body. The client gates it on ChatGPT auth, not on the destination's base URL (codex-rs/core/src/cyber_access_program.rs):
pub(crate) fn for_auth(auth: Option<&CodexAuth>, program: Option<CyberAccessProgram>) -> Option<AccessPrograms> {
program.filter(|_| auth.is_some_and(CodexAuth::is_chatgpt_auth)).map(AccessPrograms::from)
}
Because loopback injection keeps Codex's built-in openai provider pointed at the proxy (openai_base_url + realtime sideband override), the client still believes it is talking to the canonical ChatGPT backend and keeps the field. There is no client-side switch to suppress it, and it is not conditional on the model being requested.
The proxy forwards it verbatim, so whether a turn fails depends only on how strict the destination is:
| Destination model (same provider, same wire) |
Unknown top-level field tolerated? |
muse-spark-1.3-contributor |
No → 400 |
muse-spark-1.2-contributor |
No → 400 |
deepseek-v4.1-flash |
Yes → 200 |
grok-4.6 |
Yes → 200 |
glm-5.3 |
Yes → 200 |
Expected behaviour
Top-level fields that only OpenAI-operated destinations define should not be forwarded to third-party Responses upstreams. The proxy already does this for the per-item private field internal_chat_message_metadata_passthrough (stripInternalChatMessageMetadataPassthrough) at exactly the same boundary; the top-level private list needs the equivalent treatment.
Minimal redacted request or reproduction
# Fails: 400 unknown parameter `access_programs`
curl -sS http://127.0.0.1:10100/v1/responses \
-H 'Content-Type: application/json' \
-d '{"model":"OpenCode-Go/muse-spark-1.3-contributor","input":"hi","stream":false,"access_programs":{"cyber":"standard"}}'
# Succeeds: 200 (identical body, field omitted)
curl -sS http://127.0.0.1:10100/v1/responses \
-H 'Content-Type: application/json' \
-d '{"model":"OpenCode-Go/muse-spark-1.3-contributor","input":"hi","stream":false}'
The same body sent straight to the upstream, bypassing OpenCodex, isolates the field as the cause:
curl -sS https://opencode.ai/zen/go/v1/responses \
-H "Authorization: Bearer $OPENCODE_GO_API_KEY" \
-H 'x-opencode-session: <any-session-id>' \
-H 'Content-Type: application/json' \
-d '{"model":"muse-spark-1.3-contributor","input":"hi","access_programs":{"cyber":"standard"}}'
Actual response or error
{"model":"muse-spark-1.3-contributor","error":{"param":"access_programs","type":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error] unknown parameter `access_programs`"}}
Probe results with the same minimal body against /zen/go/v1/responses for muse-spark-1.3-contributor:
| Extra top-level field |
Result |
access_programs: {"cyber":"standard"} |
400, names access_programs |
codex_output_schema: {"type":"object"} |
400, names codex_output_schema |
totally_made_up_param: 1 |
400, names totally_made_up_param |
client_metadata, prompt_cache_key, service_tier, safety_identifier |
200 |
| (none) |
200 |
So this upstream validates the top-level response schema strictly, and the only reason the failures started today is the new client field.
Upstream documentation
No public specification defines access_programs; it appears to be OpenAI-internal (cyber access program), so a third-party gateway treating it as unknown is correct.
Suggested mapping or implementation notes
Validated locally against 2.57.0, in the same place the per-item private field is already stripped:
src/adapters/openai-responses/request-strips.ts — add stripOpenAiPrivateClientParams(body) that deletes access_programs and codex_output_schema, returns the input object unchanged when neither key is present (so the common path stays allocation-free), and passes non-objects through.
src/adapters/openai-responses/passthrough.ts — inside the existing if (!isCanonicalOpenAiForwardProvider(provider)) block, next to stripInternalChatMessageMetadataPassthrough(outBody), call it when !isOpenAiOperatedResponsesDestination(provider) so official OpenAI / ChatGPT traffic keeps the field and only third-party destinations lose it.
Verification after patching: muse-spark turns return 200 with the field present in the incoming body; a genuinely invalid parameter still returns 400 (so the change does not mask real client errors); deepseek-v4.1-flash, grok-4.6 and glm-5.3 are unaffected; the incoming raw body object is not mutated.
Note: forcing muse-spark onto the openai-chat wire is not an alternative workaround — POST /zen/go/v1/chat/completions for muse-spark-1.3-contributor returns HTTP 500 {"type":"error","error":{"type":"error","message":"Internal server error"}} (observed the same day, both via the proxy and directly), so the Responses wire is the only working one for these models.
Additional context and attachments
- Checked for duplicates: no existing issue or PR mentions
access_programs, codex_output_schema, or Codex 0.155.
- Requests and responses above are redacted: no credentials, tokens, account labels, or conversation content are included.
- The field is version-dependent (
access_programs is new in Codex 0.155; requests from Codex 0.154 and earlier did not contain it) and the same Codex build works fine on providers whose validator is lenient, which is why this only broke today and only for the strict Responses backends.
Client or integration
Codex App. Codex runtime
codex-cli 0.155.0-alpha.2.6(shipped with ChatGPT.app, installed 2026-09-17 10:03, previously0.154.0-alpha.6.2). Also reproduced with minimal direct HTTP requests against the proxy and against the upstream.Provider or upstream service
OpenCode Go (
OpenCode-Go,https://opencode.ai/zen/go/v1) — the gateway that identifies itself as "Console Go" in the error message. Affectsmuse-spark-1.3-contributorandmuse-spark-1.2-contributor; the same request shape succeeds on other models behind the same base URL.OpenCodex version
2.57.0 (installed CLI, latest on npm at the time of writing). macOS, Apple Silicon. Observed 2026-09-17.
Endpoint or capability
Inbound
POST /v1/responseson the proxy → outbound Responses passthrough to/zen/go/v1/responses(adapter: openai-responses,OpenCode-Goprovider). Request body shape / unknown-parameter handling.Current behaviour
Every routed turn to
muse-spark-1.3-contributorfails with HTTP 400:Root cause: Codex 0.155 attaches a new OpenAI-private top-level field,
access_programs, to its Responses request body. The client gates it on ChatGPT auth, not on the destination's base URL (codex-rs/core/src/cyber_access_program.rs):Because loopback injection keeps Codex's built-in
openaiprovider pointed at the proxy (openai_base_url+ realtime sideband override), the client still believes it is talking to the canonical ChatGPT backend and keeps the field. There is no client-side switch to suppress it, and it is not conditional on the model being requested.The proxy forwards it verbatim, so whether a turn fails depends only on how strict the destination is:
muse-spark-1.3-contributormuse-spark-1.2-contributordeepseek-v4.1-flashgrok-4.6glm-5.3Expected behaviour
Top-level fields that only OpenAI-operated destinations define should not be forwarded to third-party Responses upstreams. The proxy already does this for the per-item private field
internal_chat_message_metadata_passthrough(stripInternalChatMessageMetadataPassthrough) at exactly the same boundary; the top-level private list needs the equivalent treatment.Minimal redacted request or reproduction
The same body sent straight to the upstream, bypassing OpenCodex, isolates the field as the cause:
Actual response or error
{"model":"muse-spark-1.3-contributor","error":{"param":"access_programs","type":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error] unknown parameter `access_programs`"}}Probe results with the same minimal body against
/zen/go/v1/responsesformuse-spark-1.3-contributor:access_programs: {"cyber":"standard"}access_programscodex_output_schema: {"type":"object"}codex_output_schematotally_made_up_param: 1totally_made_up_paramclient_metadata,prompt_cache_key,service_tier,safety_identifierSo this upstream validates the top-level response schema strictly, and the only reason the failures started today is the new client field.
Upstream documentation
No public specification defines
access_programs; it appears to be OpenAI-internal (cyber access program), so a third-party gateway treating it as unknown is correct.Suggested mapping or implementation notes
Validated locally against 2.57.0, in the same place the per-item private field is already stripped:
src/adapters/openai-responses/request-strips.ts— addstripOpenAiPrivateClientParams(body)that deletesaccess_programsandcodex_output_schema, returns the input object unchanged when neither key is present (so the common path stays allocation-free), and passes non-objects through.src/adapters/openai-responses/passthrough.ts— inside the existingif (!isCanonicalOpenAiForwardProvider(provider))block, next tostripInternalChatMessageMetadataPassthrough(outBody), call it when!isOpenAiOperatedResponsesDestination(provider)so official OpenAI / ChatGPT traffic keeps the field and only third-party destinations lose it.Verification after patching: muse-spark turns return 200 with the field present in the incoming body; a genuinely invalid parameter still returns 400 (so the change does not mask real client errors);
deepseek-v4.1-flash,grok-4.6andglm-5.3are unaffected; the incoming raw body object is not mutated.Note: forcing muse-spark onto the
openai-chatwire is not an alternative workaround —POST /zen/go/v1/chat/completionsformuse-spark-1.3-contributorreturns HTTP 500{"type":"error","error":{"type":"error","message":"Internal server error"}}(observed the same day, both via the proxy and directly), so the Responses wire is the only working one for these models.Additional context and attachments
access_programs,codex_output_schema, or Codex 0.155.access_programsis new in Codex 0.155; requests from Codex 0.154 and earlier did not contain it) and the same Codex build works fine on providers whose validator is lenient, which is why this only broke today and only for the strict Responses backends.