目录
让 Claude Code 做稍长一点的工作时,回答写到一半会突然停住,屏幕上出现这一行。
API Error: Connection lost mid-response. The response above may be incomplete.
把这句话原样拿去搜索,能找到的资料却出奇地少。原因很明确,因为这是一个比较新的名字。Claude Code 官方错误参考里就原样写着这么一句——“在 v2.1.227 之前,Connection lost mid-response 显示为 Connection closed mid-response”。也就是说,现象本身早就存在,只是显示出来的单词从 closed 换成了 lost。网上已有的资料都是按旧名字写的,于是用新名字去搜的人什么也找不到。
本文以这次改名为起点,只依据官方文档和公开 Issue,梳理①这条消息的准确含义 ②此刻在屏幕前该做什么 ③为什么不会自动重试 ④断在哪一层的排查 ⑤用环境变量做的调整 ⑥与相似消息的区分。凡是掺进推测的地方,都会当场标出确信度。
屏幕上已经出现的内容并没有消失。官方给出的说明是,只要回复 continue,就能从最后一个已完成的块继续。
在 v2.1.227 之前显示为 Connection closed mid-response。按旧名字写的资料同样可以直接用。
断在本机、链路还是服务端,能用的手段完全不同。也有报告说原始 HTTPS 一切正常,只有 Claude Code 会掉。
1. 第一件该做的事——屏幕上的输出并没有消失
动手处理之前,先把最容易被误解的一点讲清楚。即使出现这条消息,在那之前已经流到屏幕上的内容也仍然保留着,并没有被丢掉。
官方错误参考对所有以“The response above may be incomplete.(以上响应可能不完整)”结尾的一组消息作了统一说明——当 Claude 已经完成了一个文本块或一次工具调用之后,流式传输才失败时,重新发送请求有可能把同样的工具调用执行两遍,因此 Claude Code 会原样保留已完成的部分,并附上这条提示,而不是把整轮丢弃。
因此,要做的只有三步。
Claude Code 会保留全部已完成的块,只丢弃这一轮结束时仍写到一半的最后一个块。缺掉的往往只是结尾的几句话,或者最后那次工具调用。
continue这正是官方给出的恢复步骤,让它从最后一个已完成的块接着往下走。不要从头再下一遍指令——那会把已经执行过的操作再跑一遍。
如果是在写文件或执行命令的中途断掉的,究竟做到了哪一步,以屏幕上的记录为准。先用 git status 之类看清真实状态,再往下继续。
-p 执行、Agent SDK、云端会话这类非交互会话里,如果被切断的响应只有文本、不含工具调用,Claude Code 会自己催 Claude 接着写下去——最多连续 3 次。只有把这些续写次数用完之后,才会出现这条提示。子代理也同样会自动续写。
2. 官方定义——表示“中途被切断”的4条消息
首先要明确的是,这段文字是 Claude Code 自己附上的提示,而不是 API 返回的错误响应正文。所以同样是“中途被切断”,Claude Code 也会按原因改写句尾的措辞。官方参考列出的是下面这 4 条。
API Error: Connection lost mid-response. The response above may be incomplete.
API Error: Your computer went to sleep mid-response. The response above may be incomplete.
API Error: The response stopped arriving. The response above may be incomplete.
官方的解释只有一句——“连接断了”。流本身在正常传输,但承载它的那条连接丢失了。
流传输到一半发生了 overloaded 或 5xx。按官方说法,这条显示本身是 v2.1.199 之后才有的,在那之前会丢掉中途输出,把整轮当成错误。
Claude Code 检测到电脑在响应中途进入了休眠。唤醒之后它会认定连接已经坏掉,停止继续读取。
连接一直开着,数据却不再传来,由流监视计时器中止的情况。这是停滞而不是断开,原因和对策都不一样。
请先准确读出,这 4 条里你看到的到底是哪一条。“中途被切断”的体验看上去都一样,但 Claude Code 是在分辨过原因之后才挑的措辞。如果显示的是 lost,那就是连接丢失的判定,既不是服务端返回了 5xx,也不是超时。
3. v2.1.227 把“closed”改名成了“lost”
这里是本文的核心。官方错误参考在列完 4 条说明之后,紧接着放了下面这句注记。
“在 v2.1.227 之前,Connection lost mid-response显示为Connection closed mid-response,The response stopped arriving显示为Response stalled mid-stream”
——Claude Code 官方错误参考(笔者自译)
也就是说,有两条措辞是同时被换掉的。把对应关系列成表格是这样。
| v2.1.227 之前的显示 | 现在的显示 | 含义(官方) |
|---|---|---|
Connection closed mid-response |
Connection lost mid-response |
连接断了 |
Response stalled mid-stream |
The response stopped arriving |
连接一直开着,数据却不再传来 |
Connection closed while thinking, before producing a response |
Connection lost before a response was produced |
一个字都还没输出就断了(即没有中途输出) |
Response stalled while thinking, before producing a response |
The response stalled before a response was produced |
一个字都还没输出,连接却开着停住了 |
请注意,第 3 行和本文这条消息是两回事。mid-response 是“已经输出了一部分之后才断”,before a response was produced 是“一个字都还没出来就断”——虽然同属这次改名,但含义和之后的行为都不同。详细内容在下一章说明。
弄清这次改名,会带来什么变化
在实际操作上有 3 点好处。
用“Connection closed mid-response”去搜,GitHub Issue 和解读文章会一下子多起来。既然是同一现象,读的时候不需要做任何换算。
显示的是 lost,就说明这套 Claude Code 是 v2.1.227 之后的版本。反过来显示 closed,那就比它更旧。
同一个现象被用两个名字报告过,所以搜 issue 时两种措辞都要搜,否则会漏掉已有的报告。
⚠️ v2.1.222 之前的版本,本身就可能误报。官方错误参考明确写着“v2.1.222 之前的 Claude Code,在响应已经完成之后才发生断开或停滞时也会给出这条通知,把一次完整的响应当作出错的一轮来报告”。也就是说,在旧版本上,输出其实全都到了,却只有错误提示照样冒出来。如果 claude --version 小于 2.1.222,请在开始排查之前先升级——你看到的这个错误有可能根本不存在。
4. 为什么不会自动重试
Claude Code 并不是什么都没做。按官方参考的“Automatic retries”一节,临时性的失败会以指数退避最多自动重试 10 次。既然这条消息还是出来了,那就说明Claude Code 判断“这里不该重试”。
分岔点只有一个,就是“Claude 是否已经完成了什么”。
如果连接是在 Claude 连思考在内、响应的任何一部分都还没完成时掉的,Claude Code 会用同样的退避重新发送请求,这一轮继续。即使文本已经开始往外流,也是一样。
如果思考已经结束、但文本和工具调用都还没开始,就以较短的间隔最多重发 2 次,仍然一直掉的话,就以 Connection lost before a response was produced 结束这一轮。
如果是在完成了一个文本块或一次工具调用之后(或者在思考之后已经开始输出)才断的,Claude Code 不会重新发送请求。因为那有可能把同一次工具调用执行两遍。
它改为保留已完成的部分,把已经完成的工具调用执行掉,并从结果继续这一轮,然后附上这条提示。
这个设计看着不方便,其实是往安全一侧倒的。假如它自动重发,那么“改写了文件”“执行了命令”这类有副作用的操作,就可能每断一次就重复跑一次。所以官方给出的是回复 continue,而不是重发——因为那是唯一不会让已经做完的工作重来一遍的路。
重试期间屏幕上会出现什么
重试进行时,转圈图标旁边会出现 Retrying in Ns · attempt x/y 的倒计时。标签一开始是 API error,但从 v2.1.198 起,会在第 3 次尝试时切换成具体原因(如果 CLAUDE_CODE_MAX_RETRIES 小于 3,就在最后一次尝试时切换)。
另外,如果请求还活着但 20 秒没有数据传来,在还没失败的阶段就会出现 Waiting for API response · will retry in … · check your network 这条横幅。这条显示的意思是“还没有失败”,倒计时指向的是 Claude Code 中止这条停滞连接的时刻。按官方说法,这个阈值在 v2.1.185 之前是 10 秒,措辞也不一样。
5. 究竟断在哪里——三个层次
只被告知“连接断了”,还定不下该做什么。会断的地方大致有 3 处,每一处的确认方式都不同。
Wi-Fi 切换、移动网络的瞬断、休眠、VPN 客户端重连。
确认方式:换成有线或换一条线路还会不会复现。如果是休眠导致的,会出现专用的措辞,据此就能分开。
企业代理、TLS 检查、LLM 网关、VPN。把长时间开着的流当成空闲连接掐掉的设备并不少见。
确认方式:去掉 HTTPS_PROXY 还会不会复现。用 /status 确认代理那一行。
服务方的故障,或者复用的连接其实早就死了的情况。特点是本机线路完全健康,却一直掉。
确认方式:去看 status.claude.com。如果在多条线路上都一样复现,那就不只是本机的问题。
claude --debug 的日志里有没有 Stale connection — reloaded rotated mTLS client material 来确认。
6. 现在能试的事——分层排查清单
下面按收益大、成本小的顺序从上往下排。每试一项,就确认一次还会不会复现。
| # | 要做的事 | 目的 |
|---|---|---|
| 1 | 回复 continue | 先别把损失坐实。比重来更快,也没有重复执行的风险 |
| 2 | 把 Claude Code 升到最新 | 连接相关的行为会随版本变化。v2.1.198 修复了“响应途中的短暂网络中断会中止整轮”的问题 |
| 3 | 把一轮拆短 | 把“读一大堆文件再写报告”拆成读取和撰写两步。直接缩短流开着的时间本身 |
| 4 | 去掉 VPN 和代理再复现 | 层2 的排查。去掉就好了,就要怀疑链路侧的空闲断连 |
| 5 | 换一条线路复现 | 层1 与层3 的排查。多条线路都一样,就不只是本机的问题 |
| 6 | 检查休眠设置 | 如果是长响应途中屏幕就会熄灭的环境,可能在专用措辞出现之前连接就已经坏了 |
| 7 | 去看 status.claude.com | 层3 的确认。遇到 529 时,Claude Code 自己也会把这个域名显示出来 |
| 8 | 用 claude --debug 留下记录 | 日志会写到 ~/.claude/debug/<session-id>.txt。提交报告时请附上它 |
| 9 | 确认有没有在用 SOCKS 代理 | 官方文档明确写着不支持 SOCKS 代理。如果在用,就换成别的路径 |
7. 用环境变量调整计时器与重试
为了中止安静下来的响应流,Claude Code 有4 个相互独立的计时器。官方的网络配置文档列出的清单是这样。
| 计时器 | 中止的条件 | 默认超时 |
|---|---|---|
| First-byte deadline | 发送之后,一个响应头都没有到 | 直连 API 180 秒 / 其他 300 秒(请求体每 32KB 再加 1 秒) |
| Event-level watchdog | 一个响应事件都解析不出来 | 300 秒(在所有提供方上都生效) |
| Byte-level watchdog | 包括 SSE 的 keep-alive ping 在内,一个字节都没来 | 直连 API 180 秒 / 其他 300 秒 |
| Body idle timeout | 5 分钟没有字节到来 | 5 分钟(面向直连 API 以外的提供方) |
不过,这些计时器中止之后给出的结果,基本上都落在“静默”那一侧的措辞上——和本文这条消息不是一回事。这里之所以列出来,是因为要把两者分开,就得先知道默认值,而不是说“出了 lost 就去把计时器调长”。如果是经过代理、会出现长时间沉默的环境,改这些值确实会改变停滞那一侧的症状。
重试那一侧可以用下面的变量调整。
| 环境变量 | 默认 | 效果 |
|---|---|---|
CLAUDE_CODE_MAX_RETRIES |
10 | 重试的次数。v2.1.186 之后上限是 15。在脚本里推荐调小它,让失败来得更早 |
CLAUDE_CODE_RETRY_WATCHDOG |
未设置 | 面向 CI 这类无人值守会话。设为 1 会对 429 和 529 无限重试,v2.1.199 之后还会把包含断连在内的临时错误的默认次数提高到 300 |
API_TIMEOUT_MS |
600000 | 单次请求的超时(毫秒,即 10 分钟)。线路慢或经过代理时可以调高 |
CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS |
未设置 | 只针对字节监视的超时。会被限制在 10 秒到 30 分钟之间 |
CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS |
未设置 | 直接指定收到第 1 个字节之前的期限。v2.1.242 之后可用 |
CLAUDE_CODE_MAX_RETRIES 调大,管用的是“输出出来之前就掉”的那一类失败,对中途被切断的情况不起作用。真正管用的是把一轮拆短。
8. 与相似消息的区分方法
对读者来说,这一节也许是最有实际用处的部分。虽然“中途停住了”的体验相同,但Claude Code 给出的措辞不同,原因和对策也不同。下面连同本站已有文章的对应关系一起梳理。
| 屏幕上的措辞 | 实际发生的事 | 该读哪一篇 |
|---|---|---|
Connection lost mid-response |
已经输出了一部分之后连接丢失 | 本文 |
Connection closed mid-response |
同一现象的旧名称(v2.1.227 之前) | 汇总了旧名称时期报告的closed 那一篇 |
The response stopped arriving旧: Response stalled mid-stream |
连接还活着,却陷入静默,被计时器中止 | stalled 那一篇(注意与重复循环的连锁) |
Server error mid-response |
流传输到一半服务端 5xx 或 overloaded | 529 与 500 那一篇 |
Your computer went to sleep mid-response |
Claude Code 检测到电脑在响应中途休眠 | 检查电源与休眠设置(本文第 6 章) |
Connection lost before a response was produced |
一个字都还没出来就断了(没有中途输出) | 属于会重试的情况。本文第 4 章 |
Unable to connect 与 SSL 证书错误 |
根本就没有连上 | 网络与代理那一篇 |
正文里冒出 court 或 invoke 标签 |
不是通信问题,而是工具调用没有被执行 | court 标签那一篇 |
最大的一个分岔是“屏幕上到底有没有出现过响应”。如果一个字都没出来,那就轮到怀疑连接本身或设置(代理、证书、防火墙)了。如果已经输出了一部分,那本身就是能连上的证据,与其去改设置,不如照本文的排查往下走更对。
第二个分岔是“断开,还是静默”
是连接丢失了,还是连接开着却不说话了,下一步的做法完全相反。
去怀疑链路和连接复用。把超时值调长没有意义——因为不是时间到了,而是连接本身没有了。
这时才轮到计时器出场。调整 CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS 之类还有余地,也要怀疑模型那边长时间不出声的情况。
9. 真实报告——ECONNRESET 停不下来的情况
最棘手的一种,是本机线路完全健康,却只有 Claude Code 一直掉。公开 Issue 里有 2 条验证步骤相当扎实的报告。它们要么就是用本文这个新名称报告的,要么包含紧挨着它之前那个版本的措辞。
报告者写道,在 Connection dropped (ECONNRESET) · Retrying in 17s · attempt 6/10 之后会出现 API Error: Connection lost mid-response.。在此之上他还报告说,用 curl 发出的 60KB POST,以及用原生 Node.js 的 https.request 发出的同样大小的 POST,都正常跑完,来自其他主机的长时间 SSE 也没有中断。
他把 MTU 的确认、Winsock LSP 的确认、最小配置下的复现,以及在两个互不相关的网络上的复现都做过了,结果仍然没有解决。Issue #86473 被标为重复,但仍然是 open 状态。
这一条是 Connection dropped (ECONNRESET) · Retrying in 0s · attempt 4/10。报告者写道,他把安全软件彻底卸载、VPN 过滤器、代理与 IPv6、Winsock 重置都排除完之后,仍然在 3 个网络(公司 Wi-Fi、家里 Wi-Fi、手机热点)上一样复现。
他给出的对比是:同一台机器、同一个账号,claude.ai 的聊天却毫无问题。Issue #85979 同样是 open(stale)状态。
即便如此,从这 2 条里还是能得出一件实用的事:“ping 通”“curl 通”都不能证明这个错误不会发生。用流式传输把一条连接开上好几分钟的通信,和短请求的条件不一样。与其把时间花在本机的网络检查上,不如把一轮拆短,更容易压低复现率。
10. 已经确定的事与尚未确定的事
为了避免误解,把官方能确认的和不能确认的分开列出来。
- 这条措辞在官方错误参考里有正式记载,含义是“连接断了”
- v2.1.227 之前显示为
Connection closed mid-response(同一个东西的改名) - 已经流出来的那部分输出是被刻意保留的(因为重发有可能重复执行)
- 恢复步骤是回复
continue - 输出出来之前的断开会自动重试(最多 10 次,指数退避)
- 非交互会话和子代理会自己接着写(分别从 v2.1.246 和 v2.1.257 起)
- 原始 HTTPS 一切健康,却只有 CLI 因 ECONNRESET 而掉(#86473 和 #85979 的报告)
- 同一台机器、同一个账号,浏览器版却没事的对比(#85979 的报告)
- 连接复用相关的缺陷可能牵涉其中(报告者转述的支持说明)
- 提到某些具体时段服务端有故障(同样是经由报告者)
- Anthropic 对原因的官方说明(上面 2 条 Issue 没有公开回复)
- 改名的理由。CHANGELOG 里找不到措辞变更的记载
- #86473 和 #85979 都仍然是 open
总之,症状、含义和恢复步骤在官方有文档,但为什么会断,官方说明还没有出来。在这种局面下确实管用的,不是查明原因,而是“即使断了也把损失压到最小”的做法——把一轮拆短、有副作用的操作边确认状态边推进、把版本保持在最新。这 3 条不管原因是什么都管用。
常见问题
Q1.“Connection lost mid-response”和“Connection closed mid-response”是不同的错误吗?
是同一个。正如官方错误参考写明的那样,在 v2.1.227 之前,同一个现象显示为 Connection closed mid-response。显示变了,并不意味着发生了新种类的故障。用旧名称写的资料也可以照样参考。
Q2. 在那之前的输出会消失吗?
不会消失。Claude 已经完成的块都会保留。被丢掉的只有这一轮结束时仍写到一半的最后一个块。Claude Code 之所以特意不重发、而是附上这条提示,是因为重新发送有可能把同一次工具调用执行两遍。
Q3. 回复什么才能从中断处继续?
请回复 continue。这是官方错误参考给出的恢复步骤,会让它从最后一个已完成的块接着走。如果从头再下一遍指令,已经执行过的操作有可能重复。
Q4. 把重试次数调大就能解决吗?
不能。正如第 4 章所说,这是 Claude Code 刻意避开重试的场合下的提示。CLAUDE_CODE_MAX_RETRIES(默认 10,v2.1.186 之后上限 15)管用的是“输出出来之前就掉”的那一类失败。真正管用的是把一轮拆短。
Q5. -p 和 CI(非交互执行)下也一样吗?
行为不同。按官方参考的说法,在非交互会话里,如果被切断的响应只有文本、不含工具调用,Claude Code 会自己催它接着写——最多连续 3 次。这条提示只有在把这些次数用完之后才会出现。在 v2.1.246 之前,第一次断开就会直接结束这一轮。如果在用 --output-format json,这条消息会进入 result 字段。
Q6. 在子代理(Task)里也会出现。
子代理同样会自动接着写。如果被切断的响应只有文本,Claude Code 会催子代理继续,只有把续写次数用完,这条提示才会成为最后一条消息。在 v2.1.257 之前,第一次断开就会给出这条提示。
Q7. 是我的网络不好吗?
有这个可能,但不一定只有这一个原因。Issue #86473 的报告者展示了用 curl 和原生 Node.js 发送的同样大小的 POST 都能跑完,而只有 CLI 会掉。请先去掉 VPN 和代理看还会不会复现,接着换一条线路试试。如果两边都没有变化,就可以判断这不只是本机的问题。
Q8. 把超时调长能让它变少吗?
对这条消息不能指望。因为判定是连接本身丢失了,而不是时间到了。调长计时器(CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS 等)管用的是 The response stopped arriving,也就是连接还活着却陷入静默的那一类症状。
Q9. 怎么确认自己在用哪个版本?
用 claude --version 就能确认。屏幕上显示 lost 就是 v2.1.227 之后,显示 closed 就比它更早。连接相关的行为会随版本变化,官方 CHANGELOG 里 v2.1.198 修复了“响应途中的短暂网络中断会中止整轮的问题”。升级是最值得先试的一手,但不是根治的保证——上面举的 2 条 Issue,都是在比它更新的版本上报告的。
Q10. 在企业网络里频繁出现。该看哪些设置?
官方的网络配置文档抓住了要点。①不支持 SOCKS 代理,所以不要用;②代理变量不要写在 shell 的 export 里,而要放进 ~/.claude/settings.json 的 env 块(因为在后台跑的 agent 拿不到 shell 的环境);③如果在用 mTLS,就要注意证书轮换——一共这 3 点。配置有没有被读到,可以看 claude --debug 的日志或 /status 的显示来确认。
相关文章
- API Error: Connection closed mid-response 的原因与对策——Claude Code 回答中途被切断
- Claude Code 的“court”无限循环与“Response stalled mid-stream”错误——原因与对策
- Claude Code 网络、代理与 TLS 证书错误(Unable to connect):原因与解决方法
- Claude Code 的 529 Overloaded / 500 错误:成因与应对
- Claude Code 的“court”与 invoke 标签泄露:工具调用不执行的真相与对策
- Claude Code 常见错误与对策 — 完整参考手册
参考的一手资料
- Claude Code — Error reference(官方文档):4 条措辞的定义、v2.1.227 的改名、用
continue恢复、Automatic retries 的分支、环境变量 - Claude Code — Enterprise network configuration(官方文档):4 个流监视计时器与默认值、代理设置、不支持 SOCKS、mTLS 的重新读取
- anthropics/claude-code — CHANGELOG(官方):v2.1.198“响应途中的短暂网络中断会中止整轮的问题”的修复
- Issue #86473 — ECONNRESET / Connection lost mid-response(v2.1.229 / Windows 11)
- Issue #85979 — ECONNRESET 在 v2.1.228 上仍然持续(Windows 11)
- Claude 的服务运行状态(官方状态页)