最近和 Codex 桌面端打交道比较多的朋友,大概率都被这行报错折磨过: stream disconnected before completion 。一开始我以为只是网络抖了一下,重试一次就好,结果它在一次大型重构任务里连断三次,直接把整个会话上下文都弄丢了,我才意识到这不是偶发故障,而是一整套可以拆解的链路问题。花了两周时间翻日志、抓包、换配置,我把它背后的常见诱因归纳成五类,并整理出一套可复用的排查顺序,希望能帮你下次遇到时少走弯路。

1. 先搞清楚这个报错在说什么:流式响应的生命周期与错误分类

Codex 桌面端的工作方式,不是等你提交完任务后一次性给你结果,而是通过 SSE(Server-Sent Events)建立一条长连接,把模型生成的 token 增量推给你。你在界面上看到"正在打字"的效果,本质就是这条流式通道在工作。 stream disconnected before completion 翻译成人话就是: 这条流在服务端还没有发出完成标记之前,连接就断了 。

理解这一点很关键,因为"连接断了"这件事可以从四个层面发生:

  • 连接压根没建立成功(网络层不可达)
  • 连接建立了,但等待数据的过程中超时(SSE 空闲超时)
  • 连接被服务端主动掐掉(过载、限流、策略拒绝)
  • 数据格式不兼容,客户端主动判定流无效(端点配置、模型不匹配)

更麻烦的是,Codex 的错误信息虽然都带 stream disconnected before completion 前缀,但冒号后面的后缀各不相同,这些后缀才是真正的定位线索。

我整理了常见的几种报错变体,你可以直接对照:

错误后缀 提示含义 优先排查方向
transport error: network error 传输层异常 网络链路质量
connection refused (os error 61) TCP 连接被拒绝 网络链路、服务不可达
idle timeout waiting for sse 等待事件超时 响应耗时、网关策略
stream closed before response.completed 流提前关闭 服务端、负载均衡
our servers are currently overloaded. please try again later. 服务端过载 服务状态、限流
exceeded retry limit, last status: 429 too many requests 限流触顶 账号配额、并发控制
local proxy failed while handling codex endpoint /responses. provi... 本地转发层处理失败 网关/端点配置
auth token is unavailable 认证令牌缺失 登录态、凭证存储

我见过不少人在社区里反复贴同一段报错求助,结果发现每个人原因都不一样。这就是我写这篇文章的原因——先用分类把大方向定住,再按照一套顺序去定位,比盲目重试高效得多。

2. 第一类:网络链路问题,任务刚开始就断通常不是巧合

如果你的报错后缀是 transport error: network error 或者 connection refused (os error 61) ,而且通常发生在任务发起后的十几秒内,那大概率是网络链路本身出了问题。

说一个我自己的真实案例。有段时间我的 Codex 在晚上八点后必现断流,白天一切正常。一开始我以为是服务端高峰期过载,后来发现同一时间我的视频会议也频繁掉线——问题出在路由器 NAT 会话表老化策略上,长时间没有数据包通过的 SSE 连接会被设备主动回收。白天任务小、响应快,连接空闲时间短所以没事;晚上任务大,服务端思考时间一长,中间设备的空闲超时就先到点断开了。

这类问题的排查思路是:

  1. 切换网络环境验证 :从 Wi-Fi 切到手机热点,或者从办公室切到家里,看是否复现。如果换网络后问题消失,说明问题在本机网络环境或中间设备上。
  2. 用连接测试命令分层探活 :先测 TCP 层连通性,再测 TSL 握手,最后发送一个最小 API 请求,看响应是否正常。
  3. 关注是否存在跨地域链路质量波动 :如果 API 端点和你之间存在较高跨地域延迟,丢包率只要超过 1%,长连接场景下的断流概率就会明显上升。

有一点容易被忽略: connection refused (os error 61) 在 macOS 上非常典型,它和超时不同,是目标端口主动拒绝了连接。如果你在某个时间段突然从网络错误变成连接拒绝,优先检查是不是本机安全软件、企业出口策略拦截了出站连接,或者 API 端点本身临时下线了。

另外,MTU 分片问题也会伪装成网络错误。当你的网络路径上有设备不支持大的数据包分片时,TLS 握手阶段的大证书交互就会超时失败,表现就是间歇性的握手断开。用 ping 测通不代表 TLS 能通,要测就要测完整链路。

3. 第二类:SSE 流式传输中断,长任务必现要先查心跳与空闲超时

如果你的报错是 idle timeout waiting for sse 或 stream closed before response.completed ,而且存在一个明显的规律——任务越长越容易断,短任务基本没事——那核心问题多半出在 SSE 流的空闲超时机制上。

SSE 是一条单向长连接,服务端把事件通过这条连接推给客户端。问题在于,模型在处理复杂任务时会有较长的"思考静默期",这段时间服务端不会推送任何数据。中间的网络设备、NAT 网关、负载均衡器,为了节省资源,通常会配置一个空闲回收策略——连接上如果 N 秒没有数据包,就主动把它断掉。

Codex 的客户端也有自己的等待上限,也就是报错里说的 idle timeout 。当服务端静默期超过客户端或中间设备的阈值时,任一方先放弃,这条连接就断了。

我在实践中遇到过几种典型场景:

  • 大仓库上下文构建导致首次响应极慢 :codebase 索引大、任务描述复杂时,服务端要处理很久才开始返回第一个 token,客户端等待超时。
  • 后台 compact 任务与主请求并发 :日志里能看到 error running remote compact task ,说明上下文压缩任务在后台运行时占用了连接资源,把主任务挤掉了。
  • 多个任务并行执行 :桌面端同时开多个会话,每个会话各自占用连接,带宽和本机资源被分走,静默期更容易触发各环节的超时。

排查这类问题,我建议先打开 Codex 的日志目录(macOS/Linux 下通常在 ~/.codex/log/ ,文件名类似 codex.log 或 codex-tui.log ),确认断流发生的时间点前后有没有 compact、retry 之类的记录。日志能告诉你,是客户端主动放弃的,还是连接被中间层掐断的。

处理方向上,把任务切小、关闭自动压缩、控制并发数,通常能立刻缓解。如果你的使用场景就是大任务多,那要考虑从网络链路上解决数据包"静默"的问题——比如在更稳定的网络环境里运行,或者通过配置文件调整客户端的超时容忍度。注意不同版本 Codex 的超时设置入口不一样,不要照搬老教程的参数。

4. 第三类:服务端过载与限流,429 触顶后疯狂重试只会更糟

还有一类断流,不是你的网络问题,也不是超时问题,而是服务端在高峰期忙不过来,或者你的账号触发了限流。典型报错是:

  • our servers are currently overloaded. please try again later.
  • exceeded retry limit, last status: 429 too many requests

先说 429 的机制。API 服务端一般从两个维度做限流:一是单位时间内的请求数量,二是并发连接数。Codex 这种长连接任务,一次任务从建立连接到最终完成可能持续几分钟,服务端资源一直被占用。如果你同时开了多个会话,或者账号被多个任务共享,很快就触顶。

更坑的是,Codex 客户端在断流后可能会自动重试,重试本身再次消耗配额,形成恶性循环。我自己就踩过这个坑。有次我写了个批量脚本,调 Codex 处理几十个文件,20 个任务并行跑,直接把账号打到限流,桌面端所有会话同时断开,报错清一色 429 too many requests 。等到配额恢复,脚本里的重试逻辑又立刻补刀,整个下午都在跟限流搏斗。

遇到这种报错,第一反应不应该是重试,而是先确认配额状态。具体排查顺序:

  1. 打开 API 用量面板,看当前配额消耗情况。
  2. 检查是不是有并行任务、后台任务在占用连接。
  3. 注意报错出现的时间规律——如果是北京时间晚上到凌晨的高峰期高频出现,那大概率是服务端整体过载。

在重试策略上,我的建议是采用指数退避:第一次断流后等 5 秒,第二次等 15 秒,第三次等 30 秒以上。不要用固定间隔反复点击重试。如果客户端支持查看响应头里的 Retry-After 字段,按这个字段指定的时间等待是最稳妥的。

另外提一句,很多人会把服务端过载误判成自己的网络问题。有个明显的区分点:服务端过载的报错信息里会明确提到 servers are currently overloaded 或 429 ,这是服务端明确告诉你"我扛不住了";而网络错误一般不会带这类明确的服务端状态码。看清这一点,能帮你少走很多弯路。

5. 第四类:本地网关/API端点配置与多模型接入冲突,最容易伪装成断流的配置问题

这一类的报错非常有迷惑性,因为它的表现形式和网络断流几乎一样,但根源是配置。典型报错是:

  • local proxy failed while handling codex endpoint /responses. provi...
  • 把端点切换到第三方模型服务后,出现 model is not supported 或间歇性 stream disconnected

先说背景。Codex 的 API 端点是可以配置的,社区里也有不少工具(比如常被提到的 cc switch 这类切换工具)来管理端点配置,方便用户把 Codex 接到不同的模型服务上。这本身是正常的技术操作,但配置的细节一旦出错,就会以"断流"的形态暴露出来。

我排查过不少这类问题,常见的配置坑有四个:

  1. base_url 路径拼接错误 。Codex 请求的是 /responses 路径,如果你的 base_url 指向了网关根路径,但网关要求带 /v1 前缀,请求就会在转发层报错。报错信息里出现 local proxy failed while handling codex endpoint /responses 时,优先看路径拼接。
  2. 模型名称不匹配 。Codex 默认发送的模型名(比如日志里出现的 gpt-5.6-sol 这类)不是所有模型服务都支持。你接入第三方模型时,必须用对方平台提供的模型标识,否则服务端可能直接拒绝,或者返回错误后断开连接。
  3. 鉴权 header 格式不同 。有的服务要求 Authorization: Bearer <key> ,有的要求自定义 header。格式不匹配时,服务端通常不会明确报错,而是把连接挂起一段时间后断开——这在客户端看起来就是一次典型的"断流"。
  4. SSE 事件格式不兼容 。Codex 客户端对 SSE 事件格式有要求,如果第三方网关的响应格式与 Responses API 的 SSE 协议不完全一致,客户端解析不了,就会判定流无效然后断开。

排查思路是这样的:先打开 Codex 的配置文件,一般在 ~/.codex/config.toml ,确认 model_provider 、 base_url 、 model 这几项的取值。然后用 curl 直接对端点发一个最小请求,观察响应。

我可以给一个配置示例,假设你要接入的是 DeepSeek 开放平台这类兼容接口:

curl -X POST "$YOUR_ENDPOINT/v1/responses" \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-chat",
    "input": "hello"
  }'

注意几个关键点: $YOUR_ENDPOINT 要填对完整路径, model 要用目标平台真实存在的模型名,认证信息要用目标平台签发的 key。如果 curl 能正常返回事件流,但 Codex 客户端依然断流,那基本可以锁定是 SSE 协议格式或鉴权头不兼容的问题。

这类问题的一个特征是: 用 curl 测完全没有问题,只有 Codex 客户端会断 。因为 Codex 对响应的校验比裸测严格得多,格式上有轻微偏差它都会判死。所以别用 curl 通不通作为唯一判断标准,要看完整的事件流格式。

6. 第五类:认证与会话状态异常,token 拿不到时一切白搭

最后一类根因,可能跟网络、配置都没关系,纯粹是登录态出了问题。典型报错是 auth token is unavailable 。

Codex 桌面端通常走 OAuth 登录流程,登录成功后 token 会被保存在系统凭证管理中(macOS 上是钥匙串,Windows 上是凭据管理器)。后续每个请求都会读取这个 token 来做认证。一旦这个环节出问题,请求发不出去或者认证失败,连接自然会被断开。

我遇到过的认证异常场景有三种:

  1. token 过期但客户端没有自动刷新 :长时间挂着没操作,回来后 token 已过期,刷新流程又因为种种原因失败,直接报 auth token is unavailable 。
  2. 系统凭证管理权限变更 :比如 macOS 更新后钥匙串权限提示被忽略,或者安全软件禁止了读取操作,导致客户端拿不到已保存的 token。
  3. 多端同时登录互相踢下线 :在另一台设备重新登录后,当前设备的 token 失效,表现为"上一秒还好好的,下一秒突然断流"。

排查思路很简单直接:

  • 重新登录一次,强制刷新 token,看错误是否消失。
  • 检查系统凭证管理中是否还能看到 Codex 的凭据。
  • 看一下客户端日志里有没有 auth 相关的错误输出。
  • 校准系统时间。系统时间偏差过大时,OAuth token 的签名验证会失败,这也是一个容易被忽略的隐藏原因。

和前面几类不同,认证问题通常可以通过"重新登录"快速验证。如果你重新登录后问题消失,过一段时间又复发,那就要深挖 token 刷新机制和凭证存储权限了。

7. 一套从快到慢的排查顺序,按这个流程走不会乱

前面讲了五类原因,但实际排查时你不可能每类都试一遍。我根据自己的经验整理了一套排查顺序,从成本最低的检查开始,逐级深入。这套方法的核心理念是: 先看错误文本,再查日志,再做端点测试,最后做环境对照 。

第一步,把完整的报错文本复制出来,重点关注冒号后面的部分。不同的后缀直接决定排查方向:

错误文本关键词 第一步定位 需要排查的内容
transport error / connection refused 网络链路 本机网络、中间设备、端点可达性
idle timeout / stream closed 超时/长连接 任务大小、并发数、中间设备空闲策略
overloaded / 429 / retry limit 服务端状态 配额用量、并发控制、重试策略
local proxy failed / model is not supported 端点配置 base_url、模型名、鉴权header、SSE格式
auth token 登录状态 重新登录、凭证管理、系统时间

第二步,查日志。Codex 的日志文件一般在 ~/.codex/log/ 目录下。看断流时间点附近有没有异常记录,比如认证失败、重试标记、compact 任务记录等。日志能帮你区分是客户端主动断开,还是连接被外部掐断。

第三步,做端点连通性测试。按三层来测:

# 第一层:TCP 握手测试
nc -vz api.example.com 443

# 第二层:TLS 握手测试
curl -vI https://api.example.com

# 第三层:最小 API 请求,看 SS E 事件流是否正常
curl -N -X POST "https://api.example.com/v1/responses" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"your-model","input":"hi"}'

哪一层失败,问题就锁定在哪一层。

第四步,环境对照法。同一个账号,在手机热点和办公室网络各跑一次;换一台机器再跑一次;用不同的账号在同一条网络下再跑一次。通过排列组合,把问题归因到"账号"、"设备"还是"网络环境"上。

第五步,临时降级方案。如果短时间定位不了,先用最小化配置扛过去:关闭自动压缩、拆分长任务、降低并发数、改用一个稳定的模型端点。

最后说一个很多人的通病:报错后第一反应是重试,重试不行就疯狂重试。这个习惯非常不好。重试本身会增加服务端压力,加剧限流,而且如果根因是配置问题,你重试一百次结果也是一样的。我现在的习惯是,第一次报错截图存档,第二次报错开始查日志,连续第三次就停下手头所有操作专门定位。这套流程走下来,大多数断流问题都能在十几分钟内找到方向。

老实说,这类问题最磨人的地方在于,它没有一个统一的"修复按钮",尤其是当它伪装成网络故障时。但只要你愿意花一点时间把日志和错误文本结合起来看,大部分真相其实都写在里面了。希望这套分类和排查顺序,能让你下次面对 Codex 断流时,从"抓狂"变成"心里有数"。

更多推荐