Codex 报 websocket closed by server before response.completed:先别慌,Codex 会先自己重连

2026-09-28

在 Codex 里跑任务,界面上冒出来这么一行:

stream disconnected before completion: websocket closed by server before response.completed

有时候前面还带着 Reconnecting... 2/5,有时候后面跟着一句 Falling back from WebSockets to HTTPS transport.

看到「disconnected」「closed」,第一反应多半是任务挂了。但按 Codex 的源码,这条提示出现时,Codex 会先自己想办法:重连、再换通道。这篇把它的来龙去脉拆开,告诉你什么时候可以不管,什么时候要动手。

本文依据 Codex 仓库 rust-v0.157.1(2026-09-25 发布)的源码。

一、这句话字面上在说什么

Codex 连 OpenAI 的时候,默认不是走普通的 HTTP 请求,而是开一条 WebSocket 长连接,模型的回答顺着这条连接一块块推过来。回答推完之后,服务端会发一个 response.completed 事件,告诉 Codex「这一轮说完了」。

这句报错的意思就是:服务端在发出 response.completed 之前,主动把 WebSocket 关了。

源码里它出现在 codex-api 读 WebSocket 消息的那段循环里:只要在收到完成事件之前读到了关闭帧,就生成这条错误。前面的 stream disconnected before completion: 是 Codex 给所有「流没走完就断了」的错误统一加的前缀。

所以它和你可能见过的 stream closed before response.completed 属于同一类:都是没等到 response.completed 流就断了。那一条的排查思路见文末相关阅读。

二、谁会走 WebSocket,谁不会

这一点决定了你会不会遇到它:

  • Codex 内置的 OpenAI 提供方(用 ChatGPT 账号登录,或者用 OpenAI API Key 直连),默认开启 WebSocket。
  • 你在 config.toml 里自定义的提供方([model_providers.xxx]),默认不开,除非你显式写了 supports_websockets = true。

换句话说,如果你是通过自定义提供方接的第三方模型,又没开这个开关,那你不会见到这条报错;见到了,说明走的是开了 WebSocket 的通道,通常就是内置 OpenAI。

三、它出现以后,Codex 自己会做什么

这是最值得知道的部分。源码里对这类流中断的处理分三步:

第一步,原地重连。 默认最多重连 5 次(stream_max_retries,默认 5,可配置的上限是 100)。每次重连会在界面上提示 Reconnecting... 当前次数/总次数。正式版会隐藏第一次重连的提示,所以你看到的往往是从 2/5 开始的。

第二步,换通道。 5 次都失败以后,Codex 不会马上报错,而是发一条警告:

Falling back from WebSockets to HTTPS transport.

然后把重试计数清零,改用普通的 HTTPS 流式请求,重新开始一轮重试。

第三步,这个会话里不再用 WebSocket。 源码注释写得很明白:切到 HTTPS 以后,这个会话剩下的所有轮次都走 HTTPS,不会再切回来。

所以,如果你看到的是带 Reconnecting... 的提示,或者 Falling back... 那条警告,任务并没有停,Codex 正在自救。等一等,大多数时候它会接着往下跑。

四、什么时候需要你动手

真正需要处理的是这两种情况:

情况一:切到 HTTPS 之后还是失败,这一轮最终报错了。 这时问题可能已经不在 WebSocket 本身,而在更底层的网络:代理不稳、公司网关掐长连接、网络本身在抖。WebSocket 只是先暴露出来的那个。按普通断流去查,见相关阅读里的断流排查。

情况二:每个新会话一开始都要来一遍「重连 5 次 → 切 HTTPS」。 能用,但每次都白白浪费一段重试时间。这说明你所在的网络对 WebSocket 长连接不友好,比如某些代理只放行普通 HTTPS 请求。

情况二可以先用 Codex 自带的体检命令确认:

codex doctor

输出里有一项 websocket 检查(内部名 network.websocket_reachability),会显示当前提供方是否启用了 WebSocket、以及 WebSocket 能不能连通。如果这一项给出警告(握手失败或超时时,doctor 会提示 “HTTPS fallback may still work”,即 HTTPS 回退可能仍然可用),而其它网络检查正常,就很可能是 WebSocket 被网络环境拦了。codex doctor 其它各项怎么看,见相关阅读。

五、两个容易想错的地方

一、别急着重装 Codex。 这条报错说的是连接被服务端关了,跟本地安装没关系。重装不会改变你的网络环境,也不会改变服务端的行为。

二、「重连成功了」不代表网络没问题。 如果你频繁看到 Reconnecting...,即使最后都成功了,也说明链路不稳。长任务里每次重连都要重新等响应,累积起来会明显拖慢速度。能换一个更稳的网络,收益比调参数大。

附:和这条报错相关的几个配置项

如果你用的是自定义提供方,下面这些都写在 config.toml 的 [model_providers.<名字>] 段里,默认值取自源码:

配置项默认值作用
supports_websocketsfalse(内置 OpenAI 为开启)这个提供方是否走 WebSocket
stream_max_retries5,最大可设 100流断开后原地重连的次数
stream_idle_timeout_ms300000(5 分钟)流里多久没有新数据,就当连接已经断了
websocket_connect_timeout_ms15000(15 秒)建立 WebSocket 连接最多等多久
request_max_retries4发往这个提供方的 HTTP 请求本身失败时的重试次数

其中最容易被忽略的是 stream_idle_timeout_ms。它的意思是:连接没断,但 5 分钟一个字都没回来,Codex 也会认为流已经断了,然后进入重连。所以如果你遇到的是「界面卡了好几分钟,然后才冒出断流提示」,有可能是这个空闲超时在起作用,而不是连接一开始就断了。

调这些数字之前想清楚:把重连次数调大,只是让 Codex 更有耐心,不会让网络变好。如果每次都要重连好几次才成功,更该做的是换一个稳的网络,或者查代理对长连接的处理。

附:怎么判断问题出在你这边还是服务端

一个简单的办法是换一台设备或一个网络对照:同一时间,用手机热点跑一个最简单的 Codex 任务。热点下正常、原网络下频繁断,问题在你的网络或代理;两边都断,更可能是服务端当时不稳,这时去看 OpenAI 的官方状态页,比折腾本地配置有用。

六、一句话总结

  • 看到 Reconnecting... 或 Falling back from WebSockets to HTTPS transport.:Codex 还在自救,先等;
  • 切到 HTTPS 还是失败:按普通断流查网络;
  • 每个会话开头都要切一次:跑 codex doctor 看 WebSocket 那一项,排查网络环境是否拦了长连接。

相关阅读

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。

留言讨论

评论发布后会被人工复核,违规内容将被删除。

    还没有人评论,来说说你的看法

    如果发表没有反应,可以前往联系我们告诉我们。

    这个页面有问题?

    提交时会附带当前页面地址和浏览器信息,帮助我们定位问题。不填联系方式即为匿名。