API 错误码:每一个到底在说什么

从 401 到 503,哪些值得重试,以及怎么分辨这是网关的错还是上游的错。

请求还没发出去就被网关挡下的错误

凭证问题一律 401,body 是扁平的 {"error": "..."},原因就写在那个字符串里:unauthorized、api key revoked、api key expired。重试没有意义。

钱的问题分两层:单把 key 自己的配额用完是 402 "api key quota exceeded",整个账户没有可用钱包则是 403,消息会写明哪个余额空了。Claude 系列还额外只认充值钱包,不满足返回 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"。

把状态码和 request id 打出来——客服要靠这个 id 定位记录。
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 超过该模型上限,诸如此类。

常见问题

哪些错误可以放心自动重试?
各种形态的 429 和 503 都可以——它们描述的是某一刻的状态,不是你的请求本身。502 all_providers_failed 值得带退避重试一两次。400、401、402、403 不要自动重试:在你换 key、充值或改 payload 之前,同样的请求只会得到同样的答复。
错误 body 的结构跟我的 SDK 预期不一样,为什么?
在路由之前抛出的错误——鉴权、allowlist、余额、准入——用的是网关自己的结构,不是某家 provider 的 envelope,严格按 SDK 解析器读可能识别不了。先看 HTTP 状态码,body 当诊断文本读。路由之后产生的错误,包括 all_providers_failed 和 stable 通道的各类失败,都会按你调用的那条路径的形态返回。
要怎么上报一个错误,别人才查得到?
把响应头里的 x-token-share-request-id 贴出来。它逐请求生成、通过 CORS 暴露,也是这条请求在记录里的主键。400 policy_violation 的 body 里也在 error 对象内带了 request_id,用途相同。