Claude API 错误码完全解读:401 / 403 / 429 / 500 / 529 排错指南
凌晨三点告警群炸了:Claude API 报错,服务半瘫。打开日志一看 —— {"type": "error", "error": {"type": "rate_limit_error", "message": "..."}},你下意识去搜 message 里那段英文。停。线上 anthropic api 报错时,先看 HTTP status code,再看 error.type,最后才是 message。status 决定你"该不该重试",error.type 决定"重试有没有用",message 只是给人看的辅助说明。本文把 Claude API 错误码全集讲清楚:每个状态码的根因、排错命令、SDK 处理代码。
Anthropic API 错误码总览
所有 Claude API 报错都遵循一个统一的结构:HTTP status code + JSON body。Body 里的 error.type 是机器可读的标识,error.message 是给人看的描述。
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "x-api-key header is required"
}
}
下表是你应该贴在排错手册第一页的清单:
| HTTP | error.type | 含义 | 根因 | 修复方向 |
|---|---|---|---|---|
| 400 | invalid_request_error | 请求格式错误 | JSON 字段缺失 / 类型错 / messages 为空 | 校验请求体 schema |
| 401 | authentication_error | 认证失败 | key 错 / header 错 / key 已 revoke | 检查 x-api-key 和 key 状态 |
| 403 | permission_error | 无权限 | key 没有目标资源权限 / workspace 禁用 | console 调权限 |
| 404 | not_found_error | 资源不存在 | 模型名拼错 / 跨 org 访问 / 资源已删 | 核对 model 字符串 |
| 413 | request_too_large | 请求体过大 | 超过 32MB | 切片或用 Files API |
| 429 | rate_limit_error | 限流 | ITPM / OTPM / RPM 任一超限 | 退避重试 + 升 tier |
| 500 | api_error | Anthropic 内部错误 | 服务端临时故障 | 带 idempotency 重试 |
| 529 | overloaded_error | 上游过载 | Anthropic 集群整体压力大 | 多上游 fallback |
记住一个简单规则:4xx 是你的问题(改请求),5xx 是 Anthropic 的问题(等或绕),但 429 和 529 都属于"现在不行,稍后可以"那一类,处理逻辑接近重试。
401 authentication_error
这是新接入用户最常踩的坑。401 不是模糊的"认证有点问题",它非常明确地告诉你:Anthropic 没认出你是谁。常见 5 种根因:
根因 1:用了 Authorization: Bearer(从 OpenAI 切过来的人最常踩)
Anthropic 原生 API 的认证 header 是 x-api-key,不是 Authorization: Bearer。后者是 OpenAI 风格。如果你从 OpenAI SDK 直接换 base_url,header 名字就错了。
# 错的写法(OpenAI 风格)
curl https://api.anthropic.com/v1/messages \
-H "Authorization: Bearer sk-ant-api03-xxxxx" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model": "claude-opus-4-8", "max_tokens": 100, "messages": [{"role": "user", "content": "hi"}]}'
# 返回:
# HTTP/2 401
# {"type":"error","error":{"type":"authentication_error","message":"x-api-key header is required"}}
# 对的写法
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: sk-ant-api03-xxxxx" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model": "claude-opus-4-8", "max_tokens": 100, "messages": [{"role": "user", "content": "hi"}]}'
根因 2:API key 拼错(尾部空格 / 换行 / 不可见字符)
从浏览器复制 key 时经常带上换行符或者前后空格,shell 里 echo $ANTHROPIC_API_KEY 看着没问题,但 curl 发出去的字节就是错的。
# 用 xxd 看真实字节,留意末尾的 0a(换行)或 20(空格)
echo -n "$ANTHROPIC_API_KEY" | xxd | tail -3
# 安全做法:重新粘贴时用 read -s
read -s ANTHROPIC_API_KEY
export ANTHROPIC_API_KEY
根因 3:中间网关 / proxy 吞掉了 header
有些 corporate proxy 或 nginx 配置只透传白名单 header,x-api-key 这种自定义名字会被吞掉。排查方法是在网关后端打印接收到的 header 列表,或者用 curl --trace-ascii 看实际发出去的字节流。
curl --trace-ascii /tmp/trace.log https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'
grep -i "x-api-key" /tmp/trace.log
# 如果 grep 不到,说明客户端就没发出去
# 如果 grep 到了但仍然 401,说明 proxy 吞了
根因 4:Key 已经被 revoke
API key 可以从 Anthropic Console 主动 revoke。如果同事撤销了某个 key 但你的环境变量还在用,就会持续 401。这种情况下 error.message 通常是 "Invalid API Key" 或 "API key not found"。
# 快速校验 key 是否还有效(用最便宜的 Haiku + max_tokens=1)
curl -s -o /dev/null -w "%{http_code}\n" https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"."}]}'
# 200 → key 有效
# 401 → key 无效
# 429 → key 有效但被限流
根因 5:缺少 anthropic-version header
Anthropic 强制要求所有请求带 anthropic-version,缺失时会报 400 而不是 401,但有些旧版本的网关把它误当成认证问题转译成 401。当前推荐版本:anthropic-version: 2023-06-01。
403 permission_error
401 和 403 经常被混用,但语义不同:401 = "我不认识你",403 = "我认识你,但你不能做这个"。常见 4 种根因:
根因 1:Workspace 级别禁用
Anthropic Console 支持把整个 workspace 禁用(比如欠费、违规、人工审核中)。这种情况下 workspace 下所有 key 都会拿到 403。error.message 通常是 "Your account is not authorized to access this resource"。
根因 2:Restricted key 越权
Anthropic 支持创建权限受限的 key(比如只能调用某些模型或某些 endpoint)。如果 key 没有权限调用 Opus,但你尝试 "model": "claude-opus-4-8",就会拿到 403。
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $RESTRICTED_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model": "claude-opus-4-8", "max_tokens": 10, "messages": [{"role":"user","content":"hi"}]}'
# {"type":"error","error":{"type":"permission_error","message":"This API key does not have access to model claude-opus-4-7"}}
根因 3:跨 organization 访问 message_batch / file
每个 organization 创建的 batch 和 file 只能由该 org 内的 key 访问。如果你拿 A org 的 key 去查 B org 创建的 message_batch_id,返回的是 403,不是 404(Anthropic 故意不告诉你"它存在"以防探测)。
根因 4:Beta feature 未开通
某些 beta 功能需要在 Console 主动开启。比如使用 PDF beta 时缺少 anthropic-beta: pdfs-2024-09-25 header,或者 workspace 没有 enroll 该 beta,会返回 403。
# 排查 403 的标准命令:
curl -i https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-opus-4-8","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'
# 重点看响应 header:
# request-id: req_xxxxxxxxxxxxxxxx ← 提工单时贴这个
# 然后去 console 对照 key 的权限范围
404 not_found_error
404 在 Claude API 里有三种典型场景:
场景 1:模型名拼错
这是新人最常踩的坑。Anthropic 的模型名规则是 claude-{family}-{major}-{minor},用连字符,不用点。
| 错的写法 | 对的写法 |
|---|---|
claude-opus-4.7 | claude-opus-4-7 |
claude-4-opus | claude-opus-4-7 |
claude-sonnet-4.6 | claude-sonnet-4-6 |
claude-3.5-sonnet | claude-haiku-4-5(注:已升级) |
场景 2:废弃模型
旧的 model alias 可能已经被废弃。检查请求时用 list_models endpoint 拿当前可用列表:
curl https://api.anthropic.com/v1/models \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" | jq '.data[].id'
场景 3:跨 organization 隔离
访问 /v1/messages/batches/{batch_id} 或 /v1/files/{file_id} 时,资源 id 必须属于当前 key 所在的 organization。Anthropic 对跨 org 访问的策略是返回 404 或 403,不会泄漏"该资源存在于其他 org"。
413 request_too_large
Messages API 单次请求体硬上限是 32MB(包含所有 messages + system + tools 的 JSON 序列化大小)。Files API 单文件上限 500MB。
如果你在 base64 嵌入大 PDF / 大图 / 大代码 dump,很容易撞 413。
# 触发 413 的典型场景
python -c "
import base64, json
with open('big_doc.pdf', 'rb') as f:
data = base64.b64encode(f.read()).decode()
print(f'PDF base64 size: {len(data) / 1024 / 1024:.1f} MB')
# 如果 > 32MB,messages 请求一定 413
"
解法 1:用 Files API
# 第一步:上传文件,拿 file_id
curl https://api.anthropic.com/v1/files \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: files-api-2025-04-14" \
-F "file=@big_doc.pdf"
# 返回 {"id": "file_xxxxx", ...}
# 第二步:在 messages 里引用 file_id,请求体只有几百字节
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: files-api-2025-04-14" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-4-8",
"max_tokens": 1024,
"messages": [{
"role": "user",
"content": [
{"type": "document", "source": {"type": "file", "file_id": "file_xxxxx"}},
{"type": "text", "text": "总结这份文档"}
]
}]
}'
解法 2:语义切片
对长代码 / 长文档场景,简单截断会丢失上下文。按章节标题、函数边界、段落分隔符切分,每片单独跑总结,最后合并。
429 rate_limit_error
这是生产环境最频繁遇到的错误。Anthropic 同时维护三种限流维度,任意一种超限都返回 429:
| 维度 | 含义 | 响应 header |
|---|---|---|
| RPM | 每分钟请求数 | anthropic-ratelimit-requests-* |
| ITPM | 每分钟输入 token 数 | anthropic-ratelimit-input-tokens-* |
| OTPM | 每分钟输出 token 数 | anthropic-ratelimit-output-tokens-* |
触发 429 时,响应 header 会告诉你具体哪一种限流以及剩余配额:
HTTP/2 429
anthropic-ratelimit-requests-limit: 1000
anthropic-ratelimit-requests-remaining: 0
anthropic-ratelimit-requests-reset: 2026-05-26T03:42:18Z
anthropic-ratelimit-input-tokens-limit: 200000
anthropic-ratelimit-input-tokens-remaining: 14523
anthropic-ratelimit-input-tokens-reset: 2026-05-26T03:42:18Z
anthropic-ratelimit-output-tokens-limit: 80000
anthropic-ratelimit-output-tokens-remaining: 0
anthropic-ratelimit-output-tokens-reset: 2026-05-26T03:42:18Z
retry-after: 18
看哪个 remaining: 0,就知道是哪个维度卡住了。retry-after(秒)是 Anthropic 建议的重试时间。
指数退避(Python)
import time, random, anthropic
from anthropic import APIStatusError
client = anthropic.Anthropic()
def call_with_retry(messages, max_retries=5):
for attempt in range(max_retries):
try:
return client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=messages,
)
except APIStatusError as e:
if e.status_code != 429:
raise
# 优先用 retry-after,没有就指数退避
retry_after = int(e.response.headers.get("retry-after", 0))
wait = retry_after if retry_after > 0 else (2 ** attempt) + random.random()
print(f"429 hit, waiting {wait:.1f}s (attempt {attempt+1}/{max_retries})")
time.sleep(wait)
raise RuntimeError("Max retries exceeded")
指数退避(Node / TypeScript)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function callWithRetry(messages: any[], maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
messages,
});
} catch (e: any) {
if (e.status !== 429) throw e;
const retryAfter = parseInt(e.headers?.["retry-after"] ?? "0", 10);
const wait = retryAfter > 0
? retryAfter * 1000
: (2 ** attempt) * 1000 + Math.random() * 1000;
console.warn(`429 hit, waiting ${wait}ms (attempt ${attempt + 1})`);
await new Promise(r => setTimeout(r, wait));
}
}
throw new Error("Max retries exceeded");
}
指数退避(Go)
package main
import (
"context"
"errors"
"math/rand"
"strconv"
"time"
"github.com/anthropics/anthropic-sdk-go"
)
func callWithRetry(ctx context.Context, client *anthropic.Client, params anthropic.MessageNewParams) (*anthropic.Message, error) {
var lastErr error
for attempt := 0; attempt < 5; attempt++ {
msg, err := client.Messages.New(ctx, params)
if err == nil {
return msg, nil
}
var apiErr *anthropic.Error
if !errors.As(err, &apiErr) || apiErr.StatusCode != 429 {
return nil, err
}
wait := time.Duration(1< 0 {
wait = time.Duration(ra) * time.Second
}
time.Sleep(wait)
lastErr = err
}
return nil, lastErr
}
降低 ITPM 触顶概率
长会话场景 ITPM 是头号瓶颈,因为每轮对话都要把完整 history 传上去。开启 Prompt Cache 后,缓存命中部分不计入 input_tokens,ITPM 用量能砍掉一半到九成。
// 把 system prompt 和长 context 放进 cache_control
const message = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
system: [{
type: "text",
text: longProjectContext, // 几十 K 的项目背景
cache_control: { type: "ephemeral" }
}],
messages: conversationHistory,
});
500 api_error
500 是 Anthropic 服务端的内部错误。和你的请求格式无关,通常是上游某条链路临时故障。
正确的处理方式是带幂等键重试。POST 请求重试时,如果不带幂等键,有可能造成重复扣费(尤其是 batch 创建场景)。
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-H "idempotency-key: req-$(uuidgen)" \
-d '{"model":"claude-opus-4-8","max_tokens":1024,"messages":[{"role":"user","content":"..."}]}'
500 vs 503 vs 504 的区别:
- 500 Anthropic 处理流程内部抛异常,可能是模型推理出问题
- 503 服务暂时不可用,通常是部署 / 维护
- 504 上游 timeout(罕见,长 prompt 推理超过 gateway 上限)
这三种统一处理:重试 2-3 次,失败后告警人工介入,不要无限重试。
529 overloaded_error
529 是 Anthropic 自定义的 status code(标准 HTTP 没有 529),含义:整个 Anthropic 集群当前负载过高,你的请求被拒绝了。
关键:529 不计入你的限流配额。它和你账号 tier 无关,是 Anthropic 容量保护机制。所有用户在同一时刻都可能拿到 529。
| 错误 | 归因 | 处理策略 |
|---|---|---|
| 429 rate_limit_error | 你的账号超限 | 退避重试 / 升级 tier |
| 529 overloaded_error | Anthropic 集群过载 | 多上游 fallback / 降级模型 |
多上游路由策略
529 高发时段(通常是欧美工作时间起始 / 模型发布后几小时)单条链路重试意义不大。生产可靠性的标准做法是配置多上游路由 —— 主链路 529 时自动切换到备用链路。
# 伪代码:多上游 fallback
async function callWithFallback(req) {
const upstreams = ["anthropic-direct", "bedrock", "vertex-ai"];
for (const u of upstreams) {
try {
return await call(u, req);
} catch (e) {
if (e.status === 529 || e.status === 503) continue;
throw e; // 其他错误直接抛出,不要 fallback
}
}
throw new Error("All upstreams overloaded");
}
注意 fallback 只对幂等请求安全。streaming 请求中途切换上游会破坏对话连续性,需要客户端做合并逻辑。
降级模型
如果你的业务能容忍质量小幅下降,Opus 拿到 529 时降级到 Sonnet,Sonnet 拿到 529 降级到 Haiku,通常能维持 SLA。
通过网关排错的优势
直连 Anthropic 时,你只能看自己客户端的日志。如果用透明转发的 AI 网关(BUZZ),排错会容易很多:
1. request-id 反查
每次请求 BUZZ 会在响应 header 里同时带回上游 request-id 和网关自己的 x-buzz-request-id。提 Anthropic 工单时贴上游的,提 BUZZ 工单时贴 BUZZ 的。
curl -i https://buzzai.cc/v1/messages \
-H "x-api-key: $BUZZ_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-opus-4-8","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}' \
| grep -iE "request-id|x-buzz-request-id"
2. 多上游自动 fallback
BUZZ 可配置多上游:Anthropic 直连优先,Bedrock 备选,Vertex AI 兜底。某条链路 529 时网关自动切换,客户端只感知到延迟略高,不会看到 5xx。这是单纯直连做不到的。
3. ratelimit header 透传
BUZZ 把上游所有 anthropic-ratelimit-* header 原样透传,你写好的 SDK 退避逻辑直接复用,不用改一行。
4. 审计日志
错误率 / latency / status code 分布在控制台一眼可见,不用自己搭 Grafana。零数据留存策略下日志只记元数据(token 计数 / 状态码 / 延迟),不记 prompt 文本,合规友好。
FAQ
Q1: Claude API 401 authentication_error 最常见的原因是什么?
最常见的是 header 写错。Anthropic 原生用 x-api-key,不是 Authorization: Bearer。如果你从 OpenAI SDK 切过来很容易踩坑。其次是 API key 拼错(尾部空格 / 换行)、key 已 revoke、网关吞掉 header、anthropic-version 缺失也会触发 401。
Q2: Claude API 429 rate_limit_error 三种限流分别是什么?
Anthropic 同时维护三种限流:input tokens per minute(ITPM)、output tokens per minute(OTPM)、requests per minute(RPM)。超过任意一种都会返回 429。响应 header 里的 anthropic-ratelimit-* 字段告诉你是哪一种触发的,以及多久会恢复。
Q3: Claude API 429 和 529 有什么区别?
429 是你超过了自己账号的限流配额,等待重试或升级 tier 即可。529 overloaded_error 是 Anthropic 整个集群过载,和你的配额无关,所有用户都可能同时收到。处理策略不同:429 应该按账号 tier 限流、529 应该走多上游 fallback。
Q4: Claude API 429 应该怎么实现指数退避?
标准做法是读取响应 header 的 retry-after 字段(秒),没有的话用指数退避加 jitter:第一次等 1 秒,第二次 2 秒,第三次 4 秒,最多重试 5 次。每次都加上 0 到 1 秒的随机抖动,避免和其他客户端同步重试导致雷暴效应。
Q5: Claude API 报 404 not_found_error 是什么原因?
三种常见原因:模型名拼错(比如把 claude-opus-4-7 写成 claude-opus-4.7 或 claude-4-opus);使用了被废弃的模型名;访问其他 organization 创建的资源(如 message_batch_id 或 file_id),不同 org 之间是完全隔离的。
Q6: Claude API 413 request_too_large 怎么解决?
Messages API 单次请求体上限 32MB,Files API 上限 500MB。如果你在直接 base64 嵌入大图或大 PDF,改用 Files API 上传后引用 file_id。代码 / 文档场景要做语义切片(按章节 / 函数边界拆分),而不是简单截断字符串。
Q7: Claude API 500 api_error 收到后应该重试吗?
应该。500 是 Anthropic 服务端临时错误,通常和你的请求无关,大部分情况下立刻重试就能成功。建议带上 idempotency-key header(POST 请求),避免重复扣费或重复创建 message_batch。重试 2-3 次还失败就走告警。
Q8: Claude API 403 permission_error 和 401 有什么区别?
401 是认证失败:key 不对、header 没写对、key 被 revoke。403 是认证通过但没权限:你的 API key 没有访问目标资源(比如某个 message_batch、某个 model)的权限,或者 workspace 级别被禁用。401 改 header 或换 key,403 要去 console 调权限。
Q9: 通过 AI 网关排错和直连 Anthropic 排错有什么不同?
透明转发型网关(BUZZ)会把上游的 anthropic-ratelimit-* / request-id 等 header 原样透传,你的排错经验和直连完全一致。同时多上游路由可以在某条链路 529 时自动 fallback 到另一条,你的客户端只感知到延迟略高,不会看到 5xx。审计日志也提供了 request_id 反查能力。
Q10: Claude Code 报 401 / 429 怎么定位?
先确认 ANTHROPIC_BASE_URL 和 ANTHROPIC_AUTH_TOKEN 两个环境变量。401 通常是 token 没生效(比如设置后没 source 配置文件,或者 token 含空格)。429 优先看错误 message 是 input_tokens 还是 output_tokens 限流,长会话场景多半是 ITPM 触顶,启用 Prompt Cache 能显著降低 input tokens 计数。
用 BUZZ 把 5xx 收敛到客户端无感
透明转发 + 多上游 fallback + ratelimit header 全保真。Claude Code 一行环境变量切换,既保留 anthropic api 报错的所有可观测性,又拿到多链路冗余。
立即注册本文最初发表于 2026-05-26,作者 BUZZ AI Gateway 团队。
如果文章有事实错误或代码示例不工作,请通过 工单系统反馈。