API 错误码:每一个到底在说什么
从 401 到 503,哪些值得重试,以及怎么分辨这是网关的错还是上游的错。
请求还没发出去就被网关挡下的错误
凭证问题一律 401,body 是扁平的 {"error": "..."},原因就写在那个字符串里:unauthorized、api key revoked、api key expired。重试没有意义。
钱的问题分两层:单把 key 自己的配额用完是 402 "api key quota exceeded",整个账户没有可用钱包则是 403,消息会写明哪个余额空了。Claude 系列还额外要求充值余额不低于 $2.00 且只认充值钱包,不满足返回 402,code 为 claude_minimum_balance。
目录里没有的 model 是 400,消息会把 id 写出来:"model not allowed: <id>"。若该 id 已退役、由专属通道接替,消息还会点名替代者,例如 "model not allowed: claude-haiku-4-5. Use stable-claude-haiku-4-5 instead."——替代者价格不同,换不换由你定,网关不替你改。model 字段为空则是 400 "model is required"。
curl -sS -o /tmp/body.json -w '%{http_code}\n' \
-D /tmp/headers.txt \
https://token-share.app/v1/messages \
-H "x-api-key: $TOKEN_SHARE_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 64,
"messages": [{"role": "user", "content": "ping"}]
}'
grep -i '^x-token-share-request-id' /tmp/headers.txt
cat /tmp/body.json容量与可用性:429 和 503
claude-sonnet-5 和 gpt-5.6-luna 这两个 id 有各自的并发上限。超了会返回 429,code 是 model_capacity_exceeded,并带上 Retry-After: 1;如果请求在该通道的队列里排过队又等超时了,code 则是 model_queue_timeout。两种都会自行恢复,退避后重试即可。
调 stable-* 时,429 表现为 stable_channel_rate_limited 或 stable_channel_busy,503 是 stable_channel_unavailable。专属通道不会回落到共享池,所以那边失败就是失败,不会被吸收掉——这正是这条通道的取舍所在。
503 且 code 为 no_cluster_capacity,意思是当时没有机器能服务该 provider。503 "key lookup temporarily unavailable, please retry" 则是另一回事:key 存储没读到,网关宁可不猜也不愿误拒一把有效的 key。这两种都值得重试。
什么时候 502 是上游的锅,不是你的
所有 provider 都失败时返回 502,body 形态跟着你走的路径:/v1/messages 是 {"type":"error","error":{"type":"api_error","code":"all_providers_failed",...}},OpenAI 形态的路径则是 {"error":{"type":"server_error","code":"all_providers_failed",...}},两者顶层都带 request_id。
另有两种更具体的 502。一种是 "upstream returned an empty body"——上游承诺有 body 却什么也没发,网关抢在你的客户端拿到「解析不了的成功」之前拦住了。另一种是上游回 200 但 body 里装着 error envelope:状态被纠正为 502,body 原样转发,好让上游自己的说法能传到你手上。
至于网关没有参与构造的状态码,会连同上游的 body 一起原样转发。所以收到一个不属于上述任何形态的 400,那是模型 provider 在说你的 payload 有问题:工具 schema 不合法、参数不支持、max_tokens 超过该模型上限,诸如此类。