跳到正文

Codex 报错 must have type response.create:先查本机 codex-router

这条 400 不是 OpenAI 返回的。先查 openai_base_url 是否指向本机 4202 端口,再按安装方式更新 codex-router。

••14 分钟阅读•OpenAI Codex
Codex 追问报 400,不是 OpenAI 报的:Codex 回合中途追问时发出 response.interrupt,被本机 127.0.0.1:4202 上的旧版 codex-router 以 400 拒收,更新到 main 后放行

回合进行中追问一句、回复问题卡片,或者中途打断,Codex 随即停下并显示:

json
{"type":"error","status":400,"error":{"type":"invalid_request_error","message":"Responses WebSocket messages must have type response.create."}}

目前公开的案例里,这条报错都不是 OpenAI 服务器返回的,而是本机的 codex-router(一个让 Codex 接入 Kimi、DeepSeek 等外部模型的本机路由代理)写出来的。旧版 codex-router 在 WebSocket 连接上只接受 response.create 这一种消息;Codex 在回合中途收到你的新输入时,会在同一条连接上再发一条 response.interrupt,旧版代理把它当成非法请求,回了 400,这个回合就断了。

修复已经在 2026 年 10 月 12 日合并进 codex-router 的 main 分支(PR #1004)。你该做什么,取决于 codex-router 是怎么装的:

你的情况下一步
用 README 推荐的一行安装脚本装的(受管 Git checkout)./bin/model-router codex update,再 ./bin/model-router codex doctor --fix,完全退出并重开 Codex
用 Homebrew 装的截至 2026 年 10 月 22 日,brew upgrade 只能拿到不含修复的 v0.6.0;先用临时办法,或改用安装脚本
暂时不能动 codex-router在 [features] 下写 instant_interrupt = false,未经实测,追问要等当前步骤结束
已经不需要外部模型codex-router uninstall(Homebrew)或 ./bin/model-router codex uninstall(checkout)
config.toml 里没有任何本机代理不属于这个已知原因,按后文的方式到 openai/codex #52221 报告

这条 400 是谁报的:本机 codex-router,不是 OpenAI

Codex 和模型服务之间通常走 Responses WebSocket:一条长时间保持的连接,双方在上面一条一条地发 JSON 消息(也叫“帧”)。每开始一个回合,Codex 发一条 type 为 response.create 的消息。

在 codex-router 0.6.0 和修复之前的 main 代码里,src/responses-websocket.mjs 有一道检查:收到的消息只要 type 不是 response.create,就回 HTTP 400、invalid_request_error 和这句原文(codex-router #1019 引用了这段代码)。报错里的英文句子就是这样来的。

为什么只在回合中途追问时出现

截至 2026 年 10 月 22 日,Codex 源码里有一个默认开启的功能 instant_interrupt。开启时,回合进行中你发追问、回复问题卡片(英文界面里叫 follow-up、question card,也就是“中途引导”,steering),Codex 会抢占正在生成的响应:在同一条连接上发出第二条消息,并等待 response.interrupt.accepted 或 response.interrupt.failed 的回复:

json
{"type":"response.interrupt","response_id":"…","mode":"discard_partial_items"}

这段逻辑在 openai/codex 源码的 responses_websocket.rs 里,只在响应已经开始之后才会发出。所以安静地等回合跑完不会触发报错,回合中途一插话就会。#52221 里的报告者在日志中也看到同样的顺序:先是 TurnInput mode: Steer,紧接着就是这个 400。

时序示意:Codex 先在同一条连接上发送 response.create,被 codex-router 放行并转发;中途追问时再发送 response.interrupt,旧版 codex-router 回 HTTP 400,回合中断;修复后两种消息都放行,同一条连接继续可用

有人猜 Codex 发的是 response.steer。OpenAI 公开的 steering 指南确实为中途引导定义了 response.steer,但截至 2026 年 10 月 22 日,Codex 源码里中途打断发的是 response.interrupt,后者在公开的 API 指南里没有记载。对一个只放行 response.create 的代理来说,这两种消息都会被拒。

用 gpt-6.1-sol 这类原生模型也会出现

很多人装 codex-router 是为了接外部模型,切回 OpenAI 的原生模型后,不会想到请求还在经过它。原因在 codex-router 写进 ~/.codex/config.toml 的受管配置块:

toml
# BEGIN codex-router-managed
openai_base_url = "http://127.0.0.1:4202/_codex-router/<generated-capability>/v1"
...
# END codex-router-managed

openai_base_url 改的是 Codex 内置 OpenAI provider 的地址,所以原生 GPT 模型的回合同样发到 127.0.0.1:4202,经由 codex-router 转发。#52221 里使用 gpt-6.1-sol 的几位报告者,事后检查配置时都发现了这一行。

这是 codex-router 旧版与 Codex 中途打断机制之间的兼容缺口,codex-router 上游已经修复。

三处确认:config.toml、报错末尾、codex-router 版本

1. config.toml 有没有把请求导向本机代理

macOS / Linux:

bash
grep -nE "openai_base_url|4202|codex-router" ~/.codex/config.toml

Windows PowerShell:

powershell
Select-String -Path "$env:USERPROFILE\.codex\config.toml" -Pattern "openai_base_url","4202","codex-router"

看到 openai_base_url 指向 127.0.0.1:4202,或者有 # BEGIN codex-router-managed、[model_providers.codex-router],就说明 Codex 的请求经过 codex-router。不熟悉这个文件的位置和结构,可以先看《Codex 沙箱与 config.toml:权限、批准和网络怎么配》。

注意: _codex-router/ 后面那一段是本机调用的凭证。不要把完整地址贴进 issue、群聊或截图,需要说明时写成 127.0.0.1:4202/…/v1。

2. 报错末尾是 response.create 还是 or response.interrupt

修复之后,codex-router 的检查同时放行 response.create 和 response.interrupt,遇到其他类型时的报错文字也变了:

报错结尾说明
must have type response.create.正在运行的 codex-router 早于修复
must have type response.create or response.interrupt.已是修复后的版本,Codex 发了 codex-router 仍不认识的另一种消息,属于新问题

3. codex-router 版本是否包含修复

用安装脚本装的,checkout 默认在 ~/.local/share/codex-router(macOS / Linux)。修复的合并提交是 a0ceb5e6:

bash
git -C ~/.local/share/codex-router merge-base --is-ancestor a0ceb5e6dd9c5c4322cf8405620af607f226ca95 HEAD && echo "已包含修复" || echo "未包含修复"

用 Homebrew 装的:

bash
brew list --versions codex-router

输出 codex-router 0.6.0 就是不含修复的版本。

代码更新了不等于已经生效:更新前启动的 codex-router 进程会一直跑旧代码,直到它重启。

另外可以运行 codex features list,看 instant_interrupt 一行的状态。如果它已经关闭,报错却照样出现,就超出了上面的解释,按最后一节的方式报告。

一行安装脚本装的:更新到 main 并运行 doctor --fix

bash
cd ~/.local/share/codex-router
./bin/model-router codex update
./bin/model-router codex doctor --fix

几个前提和细节(来自 codex-router README):

  • update 要求当前在 main 分支,且没有改动过被跟踪的文件;未跟踪的文件不影响。加 --force 会丢弃被跟踪文件的改动。
  • 更新前的版本会保留为本地回滚点,有问题可以 ./bin/model-router codex rollback。
  • 已经手动 git pull 过,也照样跑一次 update。重新运行安装脚本同样会从 main 更新。
  • doctor --fix 让生成的配置和后台服务跟新代码对齐。之后完全退出 Codex(不只是关窗口)再重新打开;如果 codex-router 是在前台终端里跑的,手动重启它。

改完用上一节第 3 步再确认一次,然后在回合进行中发一句追问试试。#52221 里有位 Windows 用户把这个修复移植到本机后,在桌面版里回复问题卡片,回合正常继续了;这只是一次测试,不代表长期稳定。

修复后的行为是:收到 response.interrupt 时取消本机发往上游的请求,丢弃未完成的内容,以 response.incomplete(原因 interrupted)结束这次响应,同一条连接继续可用。PR 里也写明,它取消的是本机的 HTTP 请求,不保证外部模型服务停止对已经发出的生成计费。用按量付费的外部模型时,频繁中途打断仍可能产生费用。

Homebrew 装的:brew upgrade 截至 10 月 22 日拿不到修复

codex-router 最新的正式版本是 2026 年 9 月 15 日发布的 v0.6.0,早于 10 月 12 日合并的修复;Homebrew 公式下载的正是 v0.6.0 的源码包。所以截至 2026 年 10 月 22 日,brew upgrade codex-router 不会带来这个修复。

codex-router 的两条更新线:Homebrew 从 9 月 15 日起停在 v0.6.0,brew upgrade 拿不到修复;安装脚本跟随 main,10 月 12 日合并 PR #1004(a0ceb5e6)后已含修复;更新后需运行 doctor --fix 并重开 Codex

可以这样选:

  • 愿意等下一个版本:关注 releases 页面,新版本发布后再 brew upgrade codex-router,等待期间用下一节的临时办法。
  • 想马上修好:先 codex-router uninstall 移除后台服务和受管的 Codex 配置,再 brew uninstall codex-router,然后按 README 改用推荐的安装脚本。安装脚本会从 main 拉代码,并重新引导你选择 provider。

暂时不能更新:instant_interrupt = false 的代价

在 ~/.codex/config.toml 里加入:

toml
[features]
instant_interrupt = false

文件里已经有 [features] 表时,把这一行加到原有的表下面,不要再写一个 [features],否则 TOML 会因为重复的表而解析失败。保存后完全退出并重开 Codex。

按 Codex 源码的逻辑,关掉 instant_interrupt 后,中途追问不再抢占正在运行的响应,也就不会发出 response.interrupt。代价是追问要等当前这一步结束才生效,中途纠偏会慢一些。这个办法没有经过实测,#52221 里最早指出原因的评论者也说自己没有试过;instant_interrupt 在源码里仍标为开发中的功能,后续版本可能改名或移除。

把它当成过渡手段:codex-router 更新到含修复的版本后,删掉这一行。

不再需要外部模型:用 uninstall 或 disable 绕开代理

如果你已经不用通过 codex-router 接入的模型,直接把它从 Codex 的请求路径上拿掉:

安装方式命令
Homebrewcodex-router uninstall,之后可以 brew uninstall codex-router
安装脚本(checkout)./bin/model-router codex uninstall;只想移除 Codex 集成、保留其他部分,用 ./bin/model-router codex disable

README 建议用这些命令,而不是手动删除 config.toml 里的受管配置块。执行后 openai_base_url 不再指向 127.0.0.1:4202,原生模型直接连 OpenAI。#52221 里有用户移除 codex-router 后,这条报错就不再出现。代价是经 codex-router 接入的 Kimi、DeepSeek 等外部模型在 Codex 里用不了了。checkout 方式的 uninstall 会保留代码、日志、备份和 provider 凭证,之后想恢复不必从头配置。

这条 400 的相关疑问:追问会不会丢、Remote 会不会出现

这是 OpenAI 服务器的故障吗?

已知案例不是。报错文字出自 codex-router 的源码;附带配置信息的报告里,openai_base_url 都指向本机地址,其中多数写明是 codex-router 的 127.0.0.1:4202。截至 2026 年 10 月 22 日,OpenAI 还没有在 #52221 里回复。

brew upgrade codex-router 能修好吗?

截至 2026 年 10 月 22 日不能。Homebrew 公式固定在 v0.6.0,修复只在 main 上,要等下一个正式版本。

被打断时,追问的内容会丢吗?

没有定论。有用户在 iPhone 上的 Codex Remote 里看到回合仍显示进行中,并出现 Continue 按钮;也有 Windows 用户反映,回复问题卡片后看不到预期的回答,只剩已执行命令的卡片。重试之前,先把追问的内容复制出来。

用 iPhone 上的 Codex Remote 也会出现吗?

会,已经有人在 Remote 对话里遇到。那位用户连接的 Mac 上,openai_base_url 同样指向 127.0.0.1:4202。要检查和修复的是运行 Codex 的那台电脑,不是手机。

能保留 codex-router,又正常中途追问吗?

能。把 codex-router 更新到包含 PR #1004 的版本即可,这正是修复的目的。更新前想继续用外部模型,就先用 instant_interrupt = false 过渡。

压缩失败之后才开始出现,两者有关系吗?

有 Windows 用户第一次遇到这条报错,是在一次上下文压缩失败之后,但他自己也无法确认两者有因果关系。压缩失败本身怎么处理,见《Codex 远程压缩失败:先看完整报错,再决定重试还是恢复会话》。

没有本机代理也出现这条报错:到 #52221 报告

如果 config.toml 里既没有 openai_base_url,也没有指向本机的自定义 provider,这条报错就超出了已知原因。#52221 中指出 codex-router 原因的评论者也说,没有代理的情况属于另一个原因,issue 应该为此保持打开。

到 openai/codex #52221 补充时,带上这些信息:

  • Codex 桌面版或 CLI 的版本号,以及操作系统;
  • 出错的时间和时区;
  • 是否设置了 openai_base_url 或自定义 provider(写“是/否”和主机端口即可);
  • codex features list 里 instant_interrupt 那一行;
  • 出错前你做了什么:追问、回复问题卡片,还是点了停止。

不要附上凭证、本机代理的完整地址或私人对话内容。

如果你已经更新了 codex-router,报错变成了以 or response.interrupt. 结尾的新文字,问题在 codex-router 这一侧,到它的 issue 区报告更合适。

如果看到的不是这个 400,而是界面反复出现 Reconnecting,那是另一类连接问题,见《Codex 一直 Reconnecting:先保住任务,再定位是哪一层断了》。

自己维护 Responses 网关:同时放行 response.interrupt

如果你自己写或维护一个给 Codex 用的 Responses 代理,这次的教训是:WebSocket 连接上不只会出现 response.create。

  • 处理 response.interrupt:字段是 response_id 和 mode: "discard_partial_items",Codex 等的回复是 response.interrupt.accepted 或 response.interrupt.failed。这个事件在公开的 API 指南里没有记载,以 Codex 源码为准。
  • 考虑 response.steer:这是 OpenAI 公开文档里的中途引导事件,只用于 GPT-6 系列、只走 WebSocket,被引导的响应以 response.incomplete(原因 steered)结束。
  • 按已知类型校验,不要一律放行:codex-router #1019 期望的做法,是对支持的类型逐一处理,对未知类型返回清楚的错误,同时保证之后的 response.create 能在同一条连接上继续。
  • 暂时不支持 WebSocket:自定义 provider 可以在 [model_providers.*] 里声明 supports_websockets = false,让 Codex 改走 HTTPS(Coder AI Gateway 的文档给出了这个办法)。这只适用于自定义 provider;openai_base_url 改道的是内置 OpenAI provider,它默认开启 WebSocket。HTTPS 路径下中途引导是否表现一致,公开资料没有说明。

自定义 provider 的写法和逐项验证方法,见《Codex 接第三方模型 API:先确认 Responses 兼容,再写 provider》。

发现内容有误,或遇到文中没覆盖的问题?请把文章地址和你看到的情况发到 hi@laozhang.ai,核实后我们会更新正文。