Claude Code 报 Connection lost mid-response 怎么办?写了一半的回答其实还能接着用
它已经写了一大段了,工具也调了两三个,然后突然停住,底下多出一行:
API Error: Connection lost mid-response. The response above may be incomplete.
或者你看到的是这个:
API Error: Connection closed mid-response. The response above may be incomplete.
再或者是这个:
API Error: Response stalled mid-stream. The response above may be incomplete.
这三条的共同点,全在后半句上:The response above may be incomplete——上面那些是真写出来了的。这和「一开始就连不上、一个字都没出来」是完全两码事,处置方式也完全不同。
这篇只讲「已经写了一半才断」这一类。
一、先说最反直觉的一条:这三条很可能是同一条报错
官方错误参考页里有一句话,把很多人的困惑一次说清了:
Before v2.1.227,
Connection lost mid-responsereadConnection closed mid-responseandThe response stopped arrivingreadResponse stalled mid-stream.
翻成人话:
Connection closed mid-response是旧文案,Connection lost mid-response是 v2.1.227 起的新文案。 同一个故障,换了个说法。Response stalled mid-stream也是旧文案,新文案叫The response stopped arriving。
所以如果你在两台机器上、或者升级前后看到了不同的字样,不代表你撞上了两个不同的毛病,很可能只是客户端版本不一样。搜索的时候记得两种文案都搜一遍,不然会漏掉一半有用的讨论。
二、closed / lost 和 stalled 的区别在哪
改名归改名,这两族的成因是真的不一样,官方在同一节里逐条给了定义:
| 报错文案(新 / 旧) | 官方给的成因 |
|---|---|
Connection lost mid-response(旧:Connection closed mid-response) | 连接断了 |
The response stopped arriving(旧:Response stalled mid-stream) | 连接还开着,但不往下发数据了,被流空闲看门狗掐掉 |
Server error mid-response | 流传到一半遇到 overloaded 或 5xx 服务端错误 |
Your computer went to sleep mid-response | 检测到电脑在响应流传输过程中睡眠了 |
差别很实在:
lost/closed是链路真的断了,TCP 层面出了事,客户端读不下去了。stalled/stopped arriving是链路没断,但没声音了。 官方描述是「连接保持打开、但停止投递数据」,所以是本地的看门狗主动放弃的。
这个区别决定了你该往哪查:前者往网络、代理、中间设备上查;后者往「是不是卡在很长的思考里」「网关有没有在缓冲」上查。
顺带一提,那条 Your computer went to sleep mid-response 值得单独记一下——合盖走开一趟回来看到断流,不一定是网络的锅,官方给它单列了一条文案。
三、为什么这一类偏偏不重试
Claude Code 对瞬时故障是会自动重试的,官方写的是最多 10 次、指数退避。那为什么这几条直接就报到你脸上了?
官方在「不重试的失败」清单里明确列了这一条:
A server error, dropped connection, or stalled stream that arrives after Claude has completed a block of text or a tool call… Claude Code could execute the same tool calls twice if it re-ran the request, so it keeps what Claude completed and shows an incomplete-response notice.
核心是幂等。 它已经跑过 Bash、已经改过文件了,这时候把整个请求重发一遍,那些副作用就会来第二遍。所以它宁可停下来告诉你「上面可能不完整」,也不敢自作主张重来。
这不是它偷懒,是它在保护你的工作区。 想明白这一点,你就不会再习惯性地把原始 prompt 复制粘贴重发一次了——那恰恰是它在替你规避的动作。
对照着看:同样是断连,如果发生在「Claude 还没完成任何一块内容」的阶段,它是会重试的,官方原话是即便已经开始吐文字也照样重发、这一轮继续。断在哪个点,决定了它重试还是撂挑子。
四、写了一半的内容,到底还能不能用
能用,而且比你想的还多。官方这段说得很细:
- 已经完成的块,全部保留。 「Claude Code keeps every block Claude completed before the error」。
- 被打断的那个块,会被丢掉。 所以最后一两句话、或者最后那个没吐完的工具调用,是没了的。
- 已经完成的工具调用,还会照常执行,而且这一轮会从它们的执行结果继续往下走——「Claude Code still runs any tool calls Claude completed and continues the turn from their results」。
第三条最容易被忽略:报错不等于什么都没发生。文件可能已经改了,命令可能已经跑了。所以断流之后的第一件事不是重来,是先看它做到哪一步了——必要时 git status 扫一眼。
五、怎么接着往下走
官方给的做法,交互式和非交互式是分开的。
交互式会话:把屏幕上剩下的内容读完,然后回一句:
continue
它会从最后一个完成的块接着往下做。
非交互模式(-p),官方分了三种情况:
- 默认文本输出:会把这一轮里它还留着的最后一个完整文本块打出来,后面跟上这条报错。如果一块都没留住(比如中途触发了压缩、把那段文本清掉了),那就只剩报错这一行。
--output-format json或stream-json:这条消息会出现在result字段里。做自动化的话这是唯一靠谱的接法——纯文本你分不清「跑完了」和「断了」。- 想接着跑:恢复会话,然后照 headless 那套发
continue。
六、无人值守才是真正的重灾区
交互式撞上这个,最多是烦。没人盯着的时候,它是会静默地少干活的。
社区里有两份把这件事量化了的报告,值得知道:
issue #83183(核对日为开放状态,已被打 stale 标签)标题就是结论——作者从本地会话记录里数出 315 次截断、散布在 130 个不同会话里。他强调的重点不是频率,是:定时任务跑的时候没人看得见那行报错,任务产出了一份短了一截的结果,然后报告成功。他也列了自己排除掉的可能:全部历史里只有 4 次 HTTP 529、0 次 500,所以不是服务端过载能解释的量级。
issue #84155(核对日为开放状态)说的是更隐蔽的一层:异步子代理的流在半路死掉之后,父会话收到的通知里 status 写的是 completed,而 summary 字段的内容恰好就是那行报错文本。作者的原话是,如果父代理按 status 分支判断,它会当这个任务干完了,默默把子代理没做完的活丢掉。他还补了一句很关键的:靠文本匹配 summary 来绕过是不可靠的,因为一个健康的子代理在汇报「我调查了这个报错」的时候,摘要里同样会出现这段话。
这两条合起来给的实操建议很清楚:
- 别让脚本只看退出码和纯文本。 用
--output-format json/stream-json,读result字段。 - 子代理的
status字段不能全信,尤其是异步派发的。摘要内容异常短、或者本身就是一句报错,要当成可疑信号。 - 任务切小。 断在第 3 步和断在第 30 步,恢复成本差得远。
七、几个和版本挂钩的行为变化
这几条都是官方文档和 CHANGELOG 里写死的版本节点,照抄不推断:
- v2.1.199 之前:服务端错误在流中途到达时,Claude Code 会把已经写出来的部分整个丢掉,然后把这一轮整体报成错误。
Server error mid-response这个变体本身也需要 v2.1.199 及以上。 - v2.1.219 之前:
claude -p的文本输出会丢掉已经产出的回答,只打一行报错。CHANGELOG 里 2.1.219 那条的原文是「Fixedclaude -ptext output dropping the answer already produced when a turn dies on a mid-stream API error」。 - v2.1.222 之前:连接在响应其实已经写完之后才断或才卡,Claude Code 也会显示这条「可能不完整」的提示、并把这一轮报成错误。CHANGELOG 2.1.222 那条写的是「Fixed “Connection closed mid-response” errors being reported on responses that had actually completed」。也就是说旧版本上有一部分这条报错是虚惊一场,内容是完整的。
- v2.1.227:就是本文开头那次改名。
结论很直接:如果你还停在 2.1.222 以下,这条报错里混着假警报,而且断流时的损失比新版本更大。 升级本身就是这一类问题里性价比最高的一步。
八、关于 stalled 那一族的两个补充
看门狗的默认值。 官方网络配置文档里列了三个独立的计时器(以核对日快照为准,这类数值会随版本调整):事件级看门狗默认 300 秒、全部 provider 都跑;字节级看门狗在直连 Anthropic API 上是 180 秒、其他环境 300 秒;另有一个 5 分钟的 body idle timeout,跑在直连 Anthropic API 之外的 provider 上。
CLAUDE_STREAM_IDLE_TIMEOUT_MS 可以调,但官方写明显式设置时最小值是 300000(5 分钟),比这更低的值会被静默地夹到下限——这条很容易踩,你以为调到 30 秒生效了,其实没有。
等待横幅不等于已经失败。 官方说明:响应流 20 秒没数据时,spinner 会显示 Waiting for API response · will retry in … · check your network。这时候请求还没失败,倒计时走到头才会中止连接、然后重试。数据恢复横幅会自己消失。另外,在 advisor 评审期间这个阈值是 90 秒而不是 20 秒,因为一次长评审本来就可能很久不出声。
九、社区 issue 里能拿走的判断信息
这几条不是官方结论,是用户报告,当线索用、别当定论:
- issue #87324(核对日为已关闭)报告的是
Connection lost mid-response出现在「助手文字转向第一个工具调用」的那个瞬间,纯文字回合不受影响。作者用--output-format stream-json抓到的字段是"error":"server_error"、"terminal_reason":"api_error",据此认为是服务端侧的错误、而不是客户端连接被掐。他抱怨的一点很实际:面向用户的提示让人去查网络、VPN、代理,把他带偏了好几个小时。 如果你已经把本地网络查了个遍还是复现,这条报告值得参考。 - issue #80619(核对日为开放状态)做了按版本的统计:2.1.210 上 1612 条助手消息、0 次
stalled mid-stream;2.1.217 是 3.0%,2.1.218 是 4.4%。作者列了网络侧的排除测试。这提示 stalled 这一族在某些版本上确实存在回归,所以「换个版本试试」在这条上不是废话。 - issue #86473、issue #85918(核对日均为开放状态)都是 Windows 环境下持续的
Connection lost mid-response,两位作者都做了网络侧排除。#86473 里提到官方支持确认了两次时间窗内的事故。遇到密集爆发时,先看是不是一段时间内的服务端状况,比逐项排查本地要快。
十、和「一开始就连不上」那一类的分界
本文从头到尾讲的都是**「已经写出来一部分了」**的场景。
如果你的情况是一个字都没出来就断,或者你看到的是 Socket is closed、Stream idle timeout - partial response received 这些文案,那属于另一类——判断路径、有没有版本修复、能不能靠 continue 恢复,答案都不一样。那一类看这篇:Claude Code 流式响应中断怎么办?Connection closed、Socket is closed、Stream idle timeout 三条分开看。
一句话分界:看有没有「The response above may be incomplete」这后半句。 有,就按本文来——内容有效、回 continue;没有,去看那一篇。
十一、总结
- 三条串很可能是同一族:
Connection closed mid-response和Connection lost mid-response是 v2.1.227 前后的新旧文案,Response stalled mid-stream的新文案是The response stopped arriving。 - closed / lost 是连接真断了,stalled 是连接开着但没数据了,排查方向不同。
- 它不重试是为了幂等——重发会把已经执行的工具调用再跑一遍。所以别复制原 prompt 重发。
- 写出来的那半截是有效的,已完成的工具调用还会继续执行并推进这一轮;被打断的最后一块会丢。
- 恢复就一个词:交互式回
continue;非交互恢复会话再发continue。 - 无人值守场景必须用结构化输出,并且别信子代理的
status。 - 版本卡在 2.1.222 以下的,先升级:假警报、
-p丢答案、丢弃部分输出,都是旧版本的行为。
核实边界:本文的报错文案定义、重试规则、恢复做法、看门狗默认值,来自 Claude Code 官方文档的 errors、env-vars、network-config 三页,以及仓库 CHANGELOG 中 2.1.199 / 2.1.219 / 2.1.222 / 2.1.227 相关条目;issue 编号与状态来自 anthropics/claude-code 仓库。未能核实的部分:我在 anthropics/claude-code 仓库的代码搜索里没有找到抛出这几条文案的实现代码(该仓库不公开 Claude Code 源码,代码搜索只命中
feed.xml),所以「由哪一层代码抛出」本文不作断言,只依据官方文档的行为描述。#87324 中「服务端 server_error」的判断是提交者依据自己的 stream-json 输出得出的,官方未在该 issue 中确认。核对日 2026-08-24,版本号与产品行为会变化,以官方文档为准。