Codex 正在读取 Responses 流,或尝试打开一个流,而它在 response.completed 事件到达前结束了:连接关闭、陷入静默、在网络层中断,或服务器报告了失败。Codex 默认会自行重试五次。冒号后打印的原因会告诉你发生了哪一种情况,并决定应从哪里排查。
错误
# Codex CLI, once its retries are spent
■ stream disconnected before completion: stream closed before response.completed
# While it retries (VS Code extension, an early-2026 build)
Reconnecting... 1/5
stream disconnected before completion: error sending request for url (https://…/responses)
# The reason after the colon varies, and it is the diagnosis:
# stream closed before response.completed
# idle timeout waiting for SSE
# error sending request (Codex before 0.156 adds: for url (…))
# An error occurred while processing your request. You can retry your request, …
# Incomplete response returned, reason: max_output_tokens原因和解决方法一览
| 原因 | 解决方法 |
|---|---|
| VPN、代理、防火墙或 TLS 检查中间设备关闭了连接 | 从另一个网络重试;如果错误消失,请让该代理或检查机制豁免 API 主机。 |
| 服务器在响应过程中失败——原因是服务器自己的消息 | 无需在本地更改:让 Codex 重试,检查提供商状态,稍后再试。 |
| 在 stream_idle_timeout_ms 内没有任何内容到达(默认 300,000 ms) | 上游停滞或代理缓冲;仅针对合理的静默提高超时。 |
| 自定义提供商在没有 response.completed 的情况下结束流 | 对其运行 curl -N:每个成功响应都必须以该事件结束。 |
| 响应被有意结束——“Incomplete response returned” | 原因中会指出 token 上限、内容过滤器或其他停止原因。重试通常会重复该问题,因此应更改请求。 |
读取冒号后的原因
Codex 对提前结束且没有更具体诊断的流使用这一错误,并附加原因。在其源代码中,单纯结束的流会给出“stream closed before response.completed”;静默时间超过 stream_idle_timeout_ms 的流会给出“idle timeout waiting for SSE”(内置 OpenAI 提供商使用的 WebSocket 传输会给出“idle timeout waiting for websocket”);线路中断的请求保留 HTTP 客户端的措辞“error sending request”(0.156 之前的构建还会附加 URL);通用的 response.failed 事件则把服务器消息放在冒号后。从 Codex 0.148 起,完全无法打开的连接——DNS、TLS、端口被拒绝——会作为单独错误“Connection failed”报告;当前构建会在等待网络时持续重试。
stream closed before response.completed the connection ended with no terminal event:
network path, server, or a provider that
never sends response.completed
idle timeout waiting for SSE no event for stream_idle_timeout_ms
error sending request the request broke on the wire: a reset, a
proxy or a middlebox (before 0.148, also
a connection that never opened)
…error decoding response body the body broke mid-read: network or middlebox
An error occurred while processing… the server's own response.failed message
Incomplete response returned, reason: … the server stopped it: a token cap, a content
filter, or whatever the reason names了解 Codex 已经会重试什么,并按提供商调整
有两个重试预算。request_max_retries(默认 4)涵盖流存在之前的 HTTP 请求;Codex 会在此处重试 5xx 响应和传输错误,但不会重试 429。stream_max_retries(默认 5)涵盖本页所有情况:每次重试都会重新发送该回合,这就是“Reconnecting... 1/5”所计数的内容;预算耗尽后,错误会保留在屏幕上,回合停止。两者上限均为 100,并且都位于 [model_providers.<id>] 块中。内置的 openai 提供商 ID 已保留,不能重新定义,因此这些是自定义提供商的调节项。
model = "gpt-5-6-sol"
model_provider = "kunavo"
[model_providers.kunavo]
name = "Kunavo"
base_url = "https://api.kunavo.com/v1"
env_key = "KUNAVO_API_KEY"
# wire_api defaults to "responses", the only supported value
stream_max_retries = 10 # dropped or failed streams (default 5, max 100)
request_max_retries = 4 # 5xx and network errors before streaming (default 4, max 100)
stream_idle_timeout_ms = 300000 # silence before giving up (default 300000)不使用 Codex 重现该流
Responses 流以一个终止事件结束,而 Codex 要求该事件为 response.completed。使用同一台机器上的 curl 发送同类请求。如果它每次都能完成,而 Codex 仍然断开,请检查 Codex 构建版本及其公开 issue;如果 curl 也中断,则先从另一个网络重复测试,再归咎于提供商。记录失败发生的时间:如果每次都在相同的运行时长后断开,说明路径上的某处存在计时器,而不是网络不稳定。
curl -sN https://api.kunavo.com/v1/responses \
-H "Authorization: Bearer $KUNAVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5-6-sol","stream":true,
"input":"Write a 600-word story about a lighthouse keeper."}' \
| grep -oE '"type": ?"response\.(completed|failed|incomplete)"'
# a healthy run prints exactly one line: "type":"response.completed"先排除网络路径,再检查提供商
在下结论前,先从第二个网络测试。在 OpenAI 论坛中,一位用户在工作机器上的错误在禁用公司 Zscaler 后立即消失;在 GPT-5.6 主题中,一位用户切换到 VPN 或手机热点后恢复正常,而另一位用户换网络后仍然失败。如果另一个网络能解决问题,请让 API 主机豁免代理或 TLS 检查,而不是提高超时。对于自定义提供商,codex doctor 会报告配置是否已加载,以及提供商的密钥变量是否存在;提供商必须提供 Responses API,因为 wire_api 没有其他值;除非它运行 Responses WebSocket 传输,否则应保持 supports_websockets 未设置。如果 curl 能顺利完成而 Codex 仍然失败,请将复现信息添加到 openai/codex issues #41340 或 #41989;这些 issue 报告了自定义 Responses 提供商出现的此错误,这些提供商在 Codex 外部可以正确流式传输,而这些 issue 在 2026 年 9 月 23 日仍处于开放状态。
如果你通过 Kunavo 调用
通过 Kunavo,GPT 模型的 /v1/responses 流是上游自己的事件流,逐帧中继:只会重写模型 ID,Kunavo 不添加 keepalive 事件。在第一个输出事件到达前,流最多会被暂存 30 秒,因此上游在此阶段报错、超时或断开连接时,如果配置了下一个通道,仍可能在该模型的下一个通道上重试。如果没有任何通道提供服务,Codex 会收到 HTTP 错误而非流——上游报错、没有响应或拒绝 Kunavo 自有密钥时为 502;原因位于 JSON code 中,例如 upstream_524 或 upstream_403(其他上游 4xx 保留自身状态)——Codex 会将其打印为 unexpected status 502 Bad Gateway: Upstream provider error,而不是此消息,并且也会重试。第一个输出事件之后,任何重试都会造成输出重复,因此无法重试:上游的 response.failed 会原样传递,Codex 会像直接从 OpenAI 收到它那样处理(通用失败会在冒号后打印其消息);上游连接在回答过程中断开,则 Kunavo 的流会在没有终止事件的情况下结束,Codex 会报告 stream closed before response.completed。无论哪种情况,都会由 Codex 自己的重试接管。Kunavo 不会限制持续流动的流——240 秒限制只涵盖等待上游标头的时间——但静默会结束流:上游 300 秒没有发送任何内容时,Kunavo 会停止读取,这与 Codex 的默认空闲值相同;边缘层会关闭 600 秒内没有传输任何字节的连接。每种失败均按零成本记录。 上面调整的提供商块是在以下页面设置的 Codex CLI 集成页面.
常见问题
“stream closed before response.completed”是什么意思?
HTTP 响应已经开始,但连接随后在 response.completed 事件到达前结束了,而 Codex 正在等待该事件。某个东西提前关闭了连接:路径中的代理或防火墙、服务器,或从未发送该事件的自定义端点。
Codex 会自动重试“stream disconnected before completion”吗?
会。Codex 会重新发送该回合,最多重试 stream_max_retries 次(默认 5 次,最多 100 次),并在重试时显示 Reconnecting... 1/5。预算耗尽后,错误会保留在屏幕上,回合停止;发送另一条消息会开始新的请求。
我应该提高 stream_idle_timeout_ms 吗?
只有当原因为“idle timeout waiting for SSE”,且静默是合理的情况下才应提高。对于“stream closed before response.completed”,它没有作用,因为此时连接是结束了,而不是进入静默。通过 Kunavo,流开始后,超过 300000 的值没有意义:Kunavo 会在上游 300 秒没有发送内容时停止读取并结束你的流。
为什么 Codex 会说“Incomplete response returned, reason: max_output_tokens”?
服务器在达到 token 上限时停止了响应,并通过 response.incomplete 事件说明了这一点。Codex 会在同一错误下报告并重试;而相同回合的重试通常会再次触及同一上限,因此应拆分任务,或使用输出上限更大的模型。通过 Kunavo,Claude 模型因达到最大 token 而停止时,也会以相同方式到达 Codex。
重试会收费吗?
每次重试都是新的请求。通过 Kunavo,上游失败的 GPT 调用——流式传输前的错误、response.failed、连接断开——均按零成本记录。如果 Codex 放弃时上游仍在工作,则会按上游报告产生的内容计费,因为这些工作已经完成。