跳到主要内容
Router One

LLM API 错误码:逐个解释,逐个修复

把 HTTP 状态码、错误 type/code 和流的终止事件一起看。400 可能是模型端点用错,402 是计费限制,429 是限流;HTTP 200 的流也可能以 response.failed 结束。先查 Dashboard → Logs 的最终请求记录,并保留 request_id,支持团队可据此关联中间尝试。

速查表

每个状态码第一步先查什么:

状态码含义第一步查什么
400请求无效,或用错了该模型的端点报错消息会点明原因:网关不提供的 Responses 特性(background、image_generation)、response_format 信封不完整,或者该模型必须走另一条路径——model '<id>' must be called via /v1/messages or /v1/chat/completions。
401API Key 无效或缺失Authorization 头需要以 `Bearer sk-…` 携带 Key——检查拼写、首尾空格,以及运行客户端的那个 shell 里环境变量是否为空。
402可用资金或 Key 预算不足先读错误消息及已有的 X-Billing-Funds-Reason 响应头。可能是在途请求预留了资金,也可能是 Key 的 maxSpend 已触顶;钱包充值不会提高 Key 消费上限。
403拒绝访问Key 已被禁用,或请求触碰了权限边界。到控制台确认 Key 状态,并核对客户端用的 base URL 是否正确。
404路径或模型不存在请求路径或模型 ID 不存在。从 /models 页复制精确的模型 ID——ID 区分大小写。
429请求频率超限触发了 Key 的 rateLimit / tokenLimitTpm 上限或上游限制。先看 Dashboard → Logs,再降低请求频率或联系支持提升限额。
499客户端取消了请求响应还没结束,客户端就关闭了连接——停止按钮、SDK 超时或网络断开。它不是上游故障,也不会故障转移:在 /v1/chat/completions 与 /v1/responses 上,Trace 记录的是上游实际报告的用量(结算规则见流式指南)。
500服务器内部错误瞬时故障。退避重试;持续出现请联系支持。
502上游响应失败查看错误正文或流内事件并保留 request_id。仅凭 502 无法判断是否所有可用线路都失败,也不能排除内层错误是限流。
503服务或模型线路暂不可用核对目录与错误 code。PROVIDER_UNAVAILABLE 可能表示当前没有可用线路,不能据此认定模型 ID 不存在;瞬时故障可采用有上限的退避重试。
504等待上游时超时Router One 会把部分 timeout 或 deadline 错误归一化成 504 PROVIDER_UNAVAILABLE,不能据此认定上游实际返回 HTTP 504。保留错误消息、端点、request_id 与时间,先区分等待响应头超时和流中途断开。
529上游过载模型上游饱和。若错误符合重试条件,且另一个健康供应商提供同一精确模型,Router One 可以尝试该路由;否则请采用有上限的退避重试。
超时未在时限内响应先识别谁停止了等待:SDK、代理、网关还是上游。客户端超时可能没有任何 HTTP 错误响应;把它的 deadline 设置与响应头、流内事件、最终请求记录对照。

还有余额却返回 402:钱包资金还是 Key 上限?

当 402 响应包含 X-Billing-Funds-Reason 时,结合其值和错误消息区分可用资金、临时预留与 Key 限额。诊断以实际返回的响应为准;客户端未展示这些字段时,保留消息和 request_id 交给支持团队,不要只看控制台余额推断原因。

实际返回的 reason下一步
wallet_reserved部分钱包资金被在途请求预留。等待结算后再检查可用金额,最终费用会影响释放量。
key_reserved在途请求占用了该 Key 的部分预算。等待结算,或到 Dashboard → API Keys 调整 maxSpend;钱包充值不会解除这个限制。
key_cap该 Key 的可用消费预算不足。按需提高或清除 maxSpend,充值不会改变这个上限。
wallet_insufficient可用钱包资金低于本次准入所需的初始预留。核对请求大小与可用金额,再减少输入或充值。
  • 若响应包含 X-Billing-Available-Balance-USD 与 X-Billing-Reserved-Balance-USD,可用它们区分钱包可用金额和已预留金额;X-Billing-Minimum-Required-USD 表示准入所需的最低初始预留,不是最终账单。
  • 配置了上限的 Key 还可能返回 X-Billing-Available-Key-Budget-USD 与 X-Billing-Reserved-Key-Budget-USD,描述独立的 Key 预算。预留释放不保证下一次一定成功,最终扣费和其他并发请求仍会改变可用金额。

为什么 HTTP 200 后还会出现 response.failed?

SSE 连接的 HTTP 200 只表示流已开始,不代表生成完成。Responses 协议需要读取 response.failed 内的 response.error,也要处理顶层 error 事件。rate_limit_error 或 Too many pending requests 表示限流;response.incomplete 则需检查 incomplete_details。保留已收到的部分输出,终止事件前意外断连应视为未完成。一旦内容已发送给客户端,就不能假定网关还能换线路重放请求。

responses-stream-error.txt
event: response.failed
data: {"type":"response.failed","response":{"status":"failed","error":{"type":"rate_limit_error","message":"Too many pending requests, please retry later"}}}

504 或 SDK 超时:到底哪一层停止了等待?

超时只说明某个等待上限已到,并不是完整归因。先确认是否收到 HTTP 响应、是否已有模型输出到达客户端。保留端点、模型 ID、可获取的 request_id、时间与时区、实际耗时和原始错误文字,不要附带 API Key。支持团队可以关联最终请求与中间尝试;仅凭状态码不能确认是哪一段网络出了问题。

观察到的证据能证明什么下一步查什么
SDK 超时,未收到 HTTP 响应客户端停止了等待,不能据此认定上游返回了 HTTP 错误。检查建连、读取和总时长限制,以及本机网络或代理错误。若请求到达网关后连接被关闭,最终日志可能记录为客户端取消。
关联的上游尝试中出现 Client.Timeout exceeded while awaiting headers网关的 HTTP 客户端等到超时时,仍未收到上游响应头;归一化的 504 不是上游实际返回 HTTP 504 的证据。交由支持核对原始尝试与该路径的超时设置。不要套用 SDK 超时,也不要假定所有端点采用相同限制。
HTTP 200,随后出现 error 事件或意外 EOFSSE 传输已打开,但生成可能失败或尚未完成。检查终止事件,保留部分输出,重试前参照流式指南;不能假定已交付的流会在另一条线路自动重新开始。
  • 指定模型的原生 /v1/responses 流允许长等待,这一策略不能泛化到所有协议和非流式请求。客户端、代理和上游自己的限制仍然存在,model:auto 也保留候选时间预算。
  • 只有真正收到上游 HTTP 响应,才能确认它的状态码。网关归一化错误、某个候选的失败与整次请求的最终结果需要分别看;符合条件的 fallback 之后,整次请求仍可能成功。

先看 trace,再动手改

Router One 的客户侧请求记录展示模型、Token、结算费用、延迟和状态。Dashboard → Logs 支持按模型和日期过滤,便于判断错误是偶发还是规律。这里不展示供应商或中间尝试;如需排查线路和故障转移链,请把 request_id 提供给支持团队。等待定价的请求可能暂未出现在列表中,查不到记录不能证明零计费。

Claude Code 里的报错

Claude Code 走 Anthropic 兼容端点 https://api.router.one——注意:结尾没有 /v1。Claude Code 里的 401/403 多数来自环境变量:没设、设在了另一个 shell、或被之前登录官方服务的会话覆盖。接网关时 Claude Code 认的是 ANTHROPIC_AUTH_TOKEN;ANTHROPIC_API_KEY 不需要设置,设了反而会多弹一次授权确认。写着 model '<id>' must be called via /v1/chat/completions 的 400 则是另一回事:你配置的模型 ID 不在 Anthropic 兼容端点上服务——换成详情页列出 POST /v1/messages 的模型(当前目录中的 Claude 系列),或者把该模型改走 /v1/chat/completions。属于鉴权问题的话,按下面设好并重启终端:

claude-code-env.sh
export ANTHROPIC_BASE_URL=https://api.router.one
export ANTHROPIC_AUTH_TOKEN=sk-your-router-one-key
unset ANTHROPIC_API_KEY

Codex CLI 里的报错

Codex CLI 使用 Responses API 协议,而许多 OpenAI 兼容中转并没有实现它——这就是 Codex 对着它们报 404 的原因。Router One 原生支持 wire_api = "responses"。在 ~/.codex/config.toml 里配置 base_url = "https://api.router.one/v1"、wire_api = "responses"、env_key = "ROUTER_ONE_API_KEY",并导出 ROUTER_ONE_API_KEY 环境变量。自定义 provider 下 Codex 不读 OPENAI_BASE_URL / OPENAI_API_KEY,而 requires_openai_auth 会让它完全忽略 env_key。若收到提到 background 或 image_generation 的 400 invalid_request,是网关拒绝了两项不支持的 Responses 特性:去掉 background = true,图片生成改走 /v1/images/generations 而不是 image_generation 工具;hosted 工具与 previous_response_id 在原生走 Responses 协议的模型上可用。写着 model '<id>' must be called via /v1/messages or /v1/chat/completions 的 400 是另一回事:Claude 家族的模型 ID 打到了 Responses 端点,而 Claude 不在这里服务——把 Codex 换成 当前目录中的 GPT 系列模型,要用 Claude 就走 Claude Code。完整步骤见 Codex Responses API 页。

常见问题

Key 看起来没问题,为什么还是 401?

三个最常见原因:环境变量设在了另一个 shell(或另一个 profile 文件)里,而不是运行客户端的那个会话;粘贴 Key 时带了尾部空格或换行;客户端读取的变量名和你设置的不一致。在同一会话里检查预期变量是否已设置即可,不要打印 Key 或把它带进截图。

哪些 Authorization 头的写法最容易导致 401?

头的值必须严格是 Bearer、一个空格、再接 Key。最常见的错误形态:scheme 写了两遍(Bearer Bearer sk-…),因为客户端会自动加前缀而环境变量里已经带了;把粘贴时连带的引号也当成了 Key 的一部分;Key 中间混入了换行或空格;Authorization 头存在但值为空,或者只发了空的 x-api-key;把控制台的登录会话 token(JWT)当成 API Key 发了;以及不带 scheme 直接写 Authorization: sk-…。要修的是头的值而不是 Key——被这样改坏的有效 Key 在查库之前就会被拒绝。

402 和 429 有什么区别?

402 关乎本次请求可用的资金或 Key 预算,也可能涉及在途请求预留;充值前先读已有的 X-Billing-Funds-Reason 诊断。429 关乎请求或 token 限额,也可能是上游限制。先看响应 code 和 message,再在有记录时到 Dashboard → Logs 关联请求。

504 PROVIDER_UNAVAILABLE 能证明上游返回了 HTTP 504 吗?

不能。Router One 可能把 timeout 或 deadline 错误归一化为该状态,即使根本没有收到上游响应头。SDK 在客户端超时又是另一种情况,可能没有 HTTP 响应。保留原始错误消息和可获取的 request_id,让支持分别核对原始上游尝试、是否发生 fallback,以及整次请求的最终结果。

遇到 5xx 需要自己写重试逻辑吗?

符合条件的 5xx 或超时,在另一个健康供应商提供同一精确模型时,可以由 Router One 重试。并非每个错误都保证重试,因此应用收到失败时仍应采用有上限的退避策略;若问题持续,请联系支持。

返回了 200,但 message 是空的,要不要重试?

先区分已完成的 Chat Completions 回复和失败的流。已完成且 usage 非零的回复可能因推理或拒答而没有正文;重试前先看 finish_reason、refusal 和 usage,因为重复调用可能再次收费。HTTP 200 伴随 response.failed、error 事件或流中断则是另一种情况:检查终止事件并保留 request_id。完全没有 usage 的空上游回复按上游错误处理。

response.failed 里出现 Too many pending requests,是 Key 无效吗?

不是。内层 rate_limit_error 表示限流,不是鉴权失败。先降低并发,再做有上限的退避重试。向支持提供 request_id、模型 ID、请求端点、时间与时区、错误 type/code,不要附 API Key。仅凭这条错误无法证明尝试了哪条线路,也不能判断故障转移是否执行。

同一个 Key,curl 能用,Claude Code 却 403?

curl 走的是 OpenAI 兼容端点;Claude Code 需要不带 /v1 后缀的 Anthropic 兼容 base URL,并设置 ANTHROPIC_AUTH_TOKEN。ANTHROPIC_API_KEY 不需要设置,保持未设即可。完整清单见 Claude Code 403 排查页。

在哪里能看到具体是哪个请求、为什么失败?

Dashboard → Logs 展示请求状态、模型、Token、结算费用和延迟,可按模型与日期过滤。客户界面不展示供应商或故障转移链。响应中有 request_id 时请保留,即使列表暂未出现记录,也可交由支持核对最终结果与中间尝试。

我遇到的是 unsupported_country_region_territory 或 insufficient_quota——这是 Router One 的报错吗?

不是——这两个都来自官方 OpenAI API,不是网关。unsupported_country_region_territory 是平台边缘的地区拦截;insufficient_quota 是伪装成 429 的账单额度耗尽。两者各有专页:地区限制报错修复页和 insufficient_quota 修复页。