Skip to content

bug: 官方 /responses 直连转发会把 Codex developer 消息转成非法 input[N],返回 400 #7

Description

@par4d15e

现象

在 Codex Desktop 中使用 New Codex MultiRouter 路由(同时启用官方 OpenAI Codex 直连链路),跨模型续聊时(例如从 MiniMax-M3 切到 gpt-5.4 后继续同一 session),会稳定复现 400

  • 用户侧报错:

    CC Switch local proxy failed while handling Codex endpoint /responses.
    Provider: New Codex MultiRouter; model: gpt-5.4
    upstream_status: HTTP 400
    cause: Invalid 'input[3].content': array too long.
    Expected an array with maximum length 0, but got an array with length 1 instead.
    code: array_above_max_length
    param: input[3].content
    endpoint: /responses
    
  • codex-router.log 中同一 trace 的 6 步事件:

    event=route_resolved
    effective_endpoint=/responses
    upstream_url=https://chatgpt.com/backend-api/codex/responses
    responses_to_chat=false
    responses_to_messages=false
    streaming=true
    
    event=auth_prepared
    auth_strategy=CodexOAuth
    auth_header_count=3
    oauth_session_header_count=4
    
    event=upstream_send
    transport=reqwest
    request_bytes=155198
    header_count=15
    timeout_ms=600000
    uses_upstream_proxy=false
    
    event=upstream_status status=400 streaming=true elapsed_ms=2434
    event=upstream_error status=400
    body_summary=Invalid_'input[3].content':_array_too_long._Expected_an_array_with_maximum_length_0,_but_got_an_array_with_length_1_instead.
    

已确认事实

  1. 失败发生时已成功连上官方上游,没有连接/网络/认证失败。
  2. route_resolvedroute_missed=false)→ request_preparedauth_preparedupstream_send 全部成功。
  3. 上游明确返回 400,不是 5xx、不是 502、不是连接失败。
  4. 同一时间窗口内,另一个 session 用同一 provider、同一官方上游能稳定拿到 200
  5. 错误字段是 input[3].content,不是 messages[N].tool_calls、不是 tool schema。

因此可以排除:

剩下的唯一合理解释是:把 Codex 内部的某条 developer 消息错误地映射成了 /responsesinput[3]

本地证据

1. 失败 session 路径:

  • ~/.codex/sessions/2026/07/01/rollout-2026-07-01T21-19-01-019f1dd5-3b1c-7bd0-8184-c0764586e8ab.jsonl:3

2. 失败 session 中开场 developer 消息内容(role: developercontent 共 6 段):

  1. <permissions instructions>
  2. <app-context>
  3. <collaboration_mode>
  4. <apps_instructions>
  5. <skills_instructions>
  6. <plugins_instructions>

developer.content[3](第 4 段)原文:

<apps_instructions>
## Apps (Connectors)
Apps (Connectors) can be explicitly triggered in user messages in the format `[$app-name](app://{connector_id})`. Apps can also be implicitly triggered as long as the context suggests usage of available apps.
An app is equivalent to a set of MCP tools within the `codex_apps` MCP.
An installed app's MCP tools are either provided to you already, or can be lazy-loaded through the `tool_search` tool. If `tool_search` is available, the apps that are searchable by `tools_search` will be listed by it.
Do not additionally call list_mcp_resources or list_mcp_resource_templates for apps.
</apps_instructions>

3. ~/.cc-switch/logs/codex-router.log 中的命中记录(同一 session 多次复现):

  • codex-router.log:2316model=gpt-5.4-mini,首次命中)
  • codex-router.log:2322model=gpt-5.4
  • codex-router.log:2742
  • codex-router.log:2753
  • codex-router.log:2807
  • codex-router.log:3433
  • codex-router.log:3811
  • codex-router.log:3817
  • codex-router.log:3847

所有命中都呈现同一 pattern:

  • effective_endpoint=/responses
  • responses_to_chat=false / responses_to_messages=false
  • status=400
  • body_summary=Invalid_'input[3].content':_array_too_long._Expected_an_array_with_maximum_length_0,_but_got_an_array_with_length_1_instead.

高概率定位

input[3].content 大概率对应的是 Codex 宿主注入的 developer 消息中的某一段。

需要说明的不确定性:

  • <apps_instructions> 本身不是 OpenAI Responses API 的请求字段,它只是 Codex 宿主拼到 developer.message.content 里的一段文本。
  • 错误指向的是 message item 的 shapeexpected 0, got 1),不是文字内容本身。
  • 当前没有抓到真实 /responses request body,因此 input[3] 究竟对应本地 developer.content[3],还是 ccswitchmulti 在拆分过程中把 developer 整条映射成了 input[3]仍需要抓包确认

为什么不是现有 issue

临时规避

按效果由强到弱:

  1. 切模型时开新会话,不要 resume 同一个 thread
  2. 改用 OAI-compatible 端点,让代理走 responses_to_chat=true 路径,绕开官方 /responses 直连校验
  3. 改用 openai_chat 转换路径

注意:以上都不能根治问题。

建议方向

  1. 正确归类 Codex 内部的 developer 消息

    • 它不是普通 user/assistant 消息
    • /responses 直连路径下,应当折叠到 instructions 或顶层 system,而不是按 content[i] 拆出多个 input[]
  2. responses_to_chat=false / responses_to_messages=false 路径下,禁止把单条 developer message 的多段 content 拆成多个 message item

    • 即使 /responses 直连,也应保持每个原始 message 一对一映射
  3. 补充诊断信息(最重要、最容易落地)

    • upstream_send 事件中新增可选的 body dump 字段(debug 级别或 env flag 控制)
    • 这样社区用户在排障时能直接看到 input[N] 的真实 rolecontent 形状
    • 当前只有 body_summary,无法定位根因
  4. 错误文案改进

  5. 针对 developer 消息加 unit test

    • 输入:Codex 开场多段 developer message
    • 期望:/responses 直连模式下生成合法 input[]
    • 当前应能复现 array too long

影响

期望维护者提供的信息

如果暂时无法复现,请至少提供以下任一项以确认根因:

  1. upstream_send 时刻加 body 字段(debug 级 / env 控制),让我抓到真实 request body
  2. 一个能在本地复现的最小 Codex session(含 developer 消息)和当前 ccswitchmulti 版本
  3. 官方 /responses 是否对 input[N]developer 消息的 content shape 有特定约束(如 content: "" 而非 content: ["..."]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions