529 overloaded — 它有两条到达路径,只有一条会被自动重试
- 先分清它是怎么来的:HTTP 529 已经被自动退避重试过了;流里的
overloaded_error走的是另一条路,标准重试机制管不到它——「跑一半突然断、一次没重试」就是这一种。 - 529 不是 429。529 是服务整体饱和,不计入你的配额,你这边没有任何杠杆——并发、缓存、档位一个都不管用。
- 能缩短等待的只有两件事:换一个同级模型继续干活,或在无人值守场景里让客户端一直重试下去。
同一个 529,有人看到的是重试了十次才放弃,有人看到的是一次都没重试就断在回答中间。这不是随机,也不是 bug——它是两条到达路径的差别。作为 HTTP 状态码返回的 529 走标准重试通道;而流式请求早就先返回了 200,过载只能作为流里的一个事件送达,官方文档明确写着这种情况下错误处理不走标准机制。搞清楚你手上是哪一种,比问「该等多久」有用得多。
你看到的报错
API Error: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}
API Error: Repeated 529 Overloaded errors. The API is at capacity — this is usually temporary. Try again in a moment. If it persists, check https://status.claude.com.
✻ API Error · Retrying in 8s · attempt 3/10
529 Overloaded
model overloaded · 模型过载,请稍后重试
还有一种,它不长这个样子,而且正是它最容易被误判成「网络断了」:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}
两条到达路径:同一个错误,不同的命运
| HTTP 529 — 请求还没开始就被拒 | 流里的 overloaded_error — 回答到一半 | |
|---|---|---|
| HTTP 状态码 | 529 | 200 — 响应头早就发出去了 |
| 错误类型 | overloaded_error | overloaded_error — 完全一样 |
| 怎么送达 | 响应体 JSON | SSE 流里的一个 event: error |
| 走标准重试吗 | 走。官方 SDK 默认退避重试 2 次;Claude Code 默认最多 10 次 | 不走。官方文档原话:这种情况下错误处理不遵循标准机制 |
| 你看到它时 | 重试预算已经用完了 | 可能一次都没重试过 |
| 典型体感 | 转圈很久,然后报错 | 字打到一半停住,像是断网 |
| 已经产生的输出 | 没有 | 已经花掉了,而且那半截回答通常留不下来 |
error 事件。
529 和 429:共用「你被拒了」的体感,其余毫无共同点
| 529 overloaded | 429 rate limit | |
|---|---|---|
| 谁的问题 | 服务整体饱和,影响所有人 | 你的组织越过了某条线 |
| 计入你的配额吗 | 不计入 | 就是配额本身 |
有 retry-after 吗 | 不保证有 | 普通限流有;配额耗尽没有 |
| 你手上的杠杆 | 没有。降并发、开缓存、提档位,全都不影响它 | 并发、缓存、档位都有效 |
| 什么时候好 | 上游容量缓过来时 | 限流几秒到几分钟;配额到重置时间 |
| 该做什么 | 等,或换模型,或让它一直重试 | 见 429 排查 |
有一个反直觉的方向值得单独点出来,因为它会把人引到完全错误的一页上去:如果你刚刚把用量陡然拉高,然后开始收到错误,那更可能是 429 而不是 529。官方文档在 529 的说明里专门补了这条提示——用量急剧上升会撞上加速度限制,回的是 429。所以「我加量了然后就过载了」这句话里,「过载」两个字多半是记错的:去看状态码,别看体感。
按这个顺序排查
1 · 先确认它到底是不是 529#
「过载」是个很容易被套用到任何一次失败上的词。先把状态码和错误类型看清楚,因为后面每一步都建立在这个判断上。
# <模型 id>:从 https://api.9coding.com/v1/models 里复制一个
curl -sS -D - -o /dev/null https://api.9coding.com/v1/messages \
-H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
-H "content-type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"<模型 id>","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}' \
| grep -iE 'http/|retry-after|request-id'
回的是 529 才是本页说的事。回 401 看 401 排查,回 429 看 429 排查,什么都回不了、连不上看 连接错误。
2 · 别在自动重试之上再叠一层手动重试#
HTTP 529 在冒到你眼前之前,已经被退避重试过了。你再按一次回车,是在重跑一个刚刚被证伪过若干次的假设。
先分清屏幕上的两种状态:带尝试次数的倒计时(形如 Retrying in 8s · attempt 3/10)说明它正在干活,别动它;没有倒计时、直接打印出来的报错才是重试预算用完之后的终态。
3 · 如果它断在回答中间,那是另一条路径,需要另一种处理#
字打到一半停住、没有倒计时、也没有明显报错——这一类多半是流里的 overloaded_error,而不是 HTTP 529。它的特征很好认:已经输出了一部分,然后戛然而止。
在交互式使用里,这一类只能自己重发。在你自己写的集成里,它需要显式处理:只判断响应状态码的代码看不见它,因为状态码是 200。同时要注意,与之体感几乎一样、但成因完全不同的还有代理空闲超时掐断长连接——判别方法见 流式回答中途断掉:让它输出短一点,如果短回答正常、长回答必断,那是超时不是过载。
4 · 换一个同级模型,是唯一能立刻见效的动作#
529 是容量事件,而容量是按模型紧张的——同一时刻,另一个同级模型往往是通的。这是本页唯一一个不靠等待就能恢复干活的办法。
/model
会话不会丢,切完继续往下干即可。可选的模型 id 从 模型列表拿,或直接读 /v1/models。
5 · 无人值守场景要改的是设置,不是心态#
CI 任务和长时间自主运行的会话里,跑到一半失败的代价远大于等待。Claude Code 为此提供了一个开关,按官方错误参考,它会让容量类错误一直重试下去,而不是在默认预算用完后失败:
export CLAUDE_CODE_RETRY_WATCHDOG=1
它有一条必须知道的边界:对写明了消费上限或额度耗尽的 429,它仍然立刻失败——因为对那类错误无限重试,只是一种更慢的失败方式。相关的还有 CLAUDE_CODE_MAX_RETRIES(默认 10)和 API_TIMEOUT_MS。这几项的默认值、上限、以及它们之间的相互作用在版本之间都变过,请按你正在跑的版本查环境变量参考。
6 · 把等待变成可观测的,而不是反复试#
529 没有 retry-after 那样可读的契约头告诉你还要多久,所以「再试一次」是一种没有信息量的动作。能查的是服务状态:先看 状态页;直连 Anthropic 时官方报错文案会直接指向它自己的状态页,走其他端点时则指向报错里写明的那个主机。
要报障就带上 request id——每一次响应都有 request-id 头,报错体里也带同一个值。9Coding 的报错响应里形如 (request id: 2026...)。这个 id 加上时间戳、模型名和完整报错文本,才能把那一次调用查出来;只说「过载了」没法排查。
什么时候这不是你的问题
下面几条同时成立,指向的就是上游容量事件,你这边再怎么调都没用:
- 同一时间段里,指向同一个端点的其他客户端也在失败,
- 它是在你的工作负载没有任何变化的情况下开始的,
- 你什么都没改,它自己就恢复了,
- 换一个同级模型立刻就通。
反过来,如果只有你一个客户端在失败、而且是在你刚刚改了什么之后开始的,那大概率不是 529——回到第 1 步把状态码看清楚。
相关报错
- 429 Too Many Requests — 你这边越线了,而且你手上有杠杆
- 流式回答中途断掉 — 体感一样,成因是超时不是过载
- Connection error — 连都没连上,那是更靠前的一层
- 全部报错速查 — 排查手册总表