让 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,就能从最后一个已完成的块继续。

② 关于名字
closed 的改名版

在 v2.1.227 之前显示为 Connection closed mid-response。按旧名字写的资料同样可以直接用。

③ 如果反复出现
按层次逐一排查

断在本机、链路还是服务端,能用的手段完全不同。也有报告说原始 HTTPS 一切正常,只有 Claude Code 会掉。

1. 第一件该做的事——屏幕上的输出并没有消失

动手处理之前,先把最容易被误解的一点讲清楚。即使出现这条消息,在那之前已经流到屏幕上的内容也仍然保留着,并没有被丢掉。

官方错误参考对所有以“The response above may be incomplete.(以上响应可能不完整)”结尾的一组消息作了统一说明——当 Claude 已经完成了一个文本块或一次工具调用之后,流式传输才失败时,重新发送请求有可能把同样的工具调用执行两遍,因此 Claude Code 会原样保留已完成的部分,并附上这条提示,而不是把整轮丢弃

因此,要做的只有三步。

步骤1
先读留下来的输出

Claude Code 会保留全部已完成的块,只丢弃这一轮结束时仍写到一半的最后一个块。缺掉的往往只是结尾的几句话,或者最后那次工具调用。

步骤2
回复 continue

这正是官方给出的恢复步骤,让它从最后一个已完成的块接着往下走。不要从头再下一遍指令——那会把已经执行过的操作再跑一遍。

步骤3
确认有副作用的操作

如果是在写文件或执行命令的中途断掉的,究竟做到了哪一步,以屏幕上的记录为准。先用 git status 之类看清真实状态,再往下继续。

非交互会话会自动接着写。 按官方参考的说法,在 -p 执行、Agent SDK、云端会话这类非交互会话里,如果被切断的响应只有文本、不含工具调用,Claude Code 会自己催 Claude 接着写下去——最多连续 3 次。只有把这些续写次数用完之后,才会出现这条提示。子代理也同样会自动续写。

2. 官方定义——表示“中途被切断”的4条消息

首先要明确的是,这段文字是 Claude Code 自己附上的提示,而不是 API 返回的错误响应正文。所以同样是“中途被切断”,Claude Code 也会按原因改写句尾的措辞。官方参考列出的是下面这 4 条。

API Error: Server error mid-response. The response above may be incomplete.
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.
本文主题
Connection lost mid-response

官方的解释只有一句——“连接断了”。流本身在正常传输,但承载它的那条连接丢失了。

服务端的失败
Server error mid-response

流传输到一半发生了 overloaded 或 5xx。按官方说法,这条显示本身是 v2.1.199 之后才有的,在那之前会丢掉中途输出,把整轮当成错误。

本机的原因
Your computer went to sleep mid-response

Claude Code 检测到电脑在响应中途进入了休眠。唤醒之后它会认定连接已经坏掉,停止继续读取

不是断开而是静默
The response stopped arriving

连接一直开着,数据却不再传来,由流监视计时器中止的情况。这是停滞而不是断开,原因和对策都不一样。

请先准确读出,这 4 条里你看到的到底是哪一条。“中途被切断”的体验看上去都一样,但 Claude Code 是在分辨过原因之后才挑的措辞。如果显示的是 lost,那就是连接丢失的判定,既不是服务端返回了 5xx,也不是超时。

3. v2.1.227 把“closed”改名成了“lost”

这里是本文的核心。官方错误参考在列完 4 条说明之后,紧接着放了下面这句注记。

“在 v2.1.227 之前,Connection lost mid-response 显示为 Connection closed mid-responseThe 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 是否重复

同一个现象被用两个名字报告过,所以搜 issue 时两种措辞都要搜,否则会漏掉已有的报告。

🟡 CHANGELOG 里没有写。 这次改名只写在官方文档一侧,在笔者查证的范围内,官方 CHANGELOG 的 v2.1.227 条目里没有关于措辞变更的记载。从用户的角度看,就成了某一天单词突然变了。请不要因为显示变了,就判断成“出现了另一个新错误”。

⚠️ 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 处,每一处的确认方式都不同

层1
本机与线路

Wi-Fi 切换、移动网络的瞬断、休眠、VPN 客户端重连。

确认方式:换成有线或换一条线路还会不会复现。如果是休眠导致的,会出现专用的措辞,据此就能分开。

层2
链路(代理、网关)

企业代理、TLS 检查、LLM 网关、VPN。把长时间开着的流当成空闲连接掐掉的设备并不少见。

确认方式:去掉 HTTPS_PROXY 还会不会复现。用 /status 确认代理那一行。

层3
服务端与连接复用

服务方的故障,或者复用的连接其实早就死了的情况。特点是本机线路完全健康,却一直掉

确认方式:去看 status.claude.com。如果在多条线路上都一样复现,那就不只是本机的问题。

容易被忽略的第 4 种可能——mTLS 证书轮换。 在企业环境里使用客户端证书时,替换证书和密钥会引发连接级别的错误(连接重置或 TLS 握手失败)。按官方的网络配置文档,Claude Code 会在遇到这类连接错误时重新读取这两个文件,并用新的一组重试。不过这种重新读取是 v2.1.232 之后的行为,在那之前会一直握着旧的一组,直到重启或重新应用配置为止。可以看 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 自己也会把这个域名显示出来
8claude --debug 留下记录日志会写到 ~/.claude/debug/<session-id>.txt。提交报告时请附上它
9确认有没有在用 SOCKS 代理官方文档明确写着不支持 SOCKS 代理。如果在用,就换成别的路径
“浏览器上的 Claude 没事”不能当判断依据。 claude.ai 的聊天和 Claude Code 的 CLI,建立连接的方式、一条连接开着的时长都不一样。一边好好的、另一边却掉,完全可能发生(实际上后面要讲的 Issue #85979 报告的就是这种情况)。最好不要断定“账号没问题,所以是设置的问题”。

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 之后可用
⚠️ 就算把重试次数调大,这条消息也不会变少。 正如第 4 章所说,它是 Claude Code 刻意避开重试的场合下给出的提示。把 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 证书错误 根本就没有连上 网络与代理那一篇
正文里冒出 courtinvoke 标签 不是通信问题,而是工具调用没有被执行 court 标签那一篇

最大的一个分岔是“屏幕上到底有没有出现过响应”。如果一个字都没出来,那就轮到怀疑连接本身或设置(代理、证书、防火墙)了。如果已经输出了一部分,那本身就是能连上的证据,与其去改设置,不如照本文的排查往下走更对。

第二个分岔是“断开,还是静默”

是连接丢失了,还是连接开着却不说话了,下一步的做法完全相反。

如果是断开(lost)

去怀疑链路和连接复用。把超时值调长没有意义——因为不是时间到了,而是连接本身没有了。

如果是静默(stopped arriving)

这时才轮到计时器出场。调整 CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS 之类还有余地,也要怀疑模型那边长时间不出声的情况。

9. 真实报告——ECONNRESET 停不下来的情况

最棘手的一种,是本机线路完全健康,却只有 Claude Code 一直掉。公开 Issue 里有 2 条验证步骤相当扎实的报告。它们要么就是用本文这个新名称报告的,要么包含紧挨着它之前那个版本的措辞。

Issue #86473(v2.1.229 / Windows 11)
原始 HTTPS 能通,只有 CLI 会断

报告者写道,在 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 状态。

Issue #85979(v2.1.228 / Windows 11)
同一台机器上浏览器版毫无问题

这一条是 Connection dropped (ECONNRESET) · Retrying in 0s · attempt 4/10。报告者写道,他把安全软件彻底卸载、VPN 过滤器、代理与 IPv6、Winsock 重置都排除完之后,仍然在 3 个网络(公司 Wi-Fi、家里 Wi-Fi、手机热点)上一样复现

他给出的对比是:同一台机器、同一个账号,claude.ai 的聊天却毫无问题Issue #85979 同样是 open(stale)状态。

🟡 关于这一章的确信度。 上面 2 条都是个人报告,并不是 Anthropic 对原因的官方说明。在 #85979 里,报告者写道支持人员告诉他“与陈旧连接复用有关的缺陷在 v2.1.227 之后应该已经修好”,但升级之后仍然复现——这是报告者转述的与支持的往来,不是公开的官方结论。同样,#86473 里提到的 2 段故障时间,也是报告者写的、由支持方告知的内容。请不要把它们当成复现条件已经确定的事实来读。

即便如此,从这 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.jsonenv 块(因为在后台跑的 agent 拿不到 shell 的环境);③如果在用 mTLS,就要注意证书轮换——一共这 3 点。配置有没有被读到,可以看 claude --debug 的日志或 /status 的显示来确认。

相关文章

参考的一手资料