错误码
/v1 会返回的每一个错误码:触发条件、是否可重试、处理方式,以及两种格式的错误体。
更新于 2026-10-24·阅读约 16 分钟
对话补全、向量与模型列表接口的错误体与 OpenAI 格式兼容,另带 request_id 与 details。/messages 使用 Anthropic 格式,见 Anthropic 格式的错误体。
json{
"error": {
"message": "请求过于频繁,请稍后再试",
"type": "rate_limit_error",
"code": "rate_limited",
"scirouter_code": "RATE_LIMITED",
"request_id": "req_88a1",
"details": { "retry_after_seconds": 12 }
}
}| 字段 | 说明 |
|---|---|
message | 供人阅读的错误说明,措辞可能变更,不用于程序分支 |
type | 按状态码映射的错误类别,粒度较粗,见 type 与状态码 |
code | 小写的平台错误码,程序按它分支。三个上游语义错误例外,取原厂兼容值(如 context_length_exceeded),见上游语义错误 |
scirouter_code | 大写的平台错误码,OpenAI 格式的错误体均返回。需要对全部错误统一分支时读取该字段 |
param | 仅参数错误时返回,指出出错的字段 |
request_id | 本次调用的编号,与响应头 X-Request-Id 相同 |
details | 附加信息,如 retry_after_seconds、limit、scope。官方 SDK 忽略该字段,不影响兼容 |
返回 details.retry_after_seconds 时,响应头 Retry-After 必定取相同的值。
报障时提供 request_id,平台按它定位单次调用。控制台请求日志可按 request_id 查到对应记录,详情页的「复制报障信息」汇总排障所需的全部信息,见可观测性。
可重试的错误
#按指数退避重试;响应带 Retry-After 时按其等待。重试须设置次数上限。
| 状态码 | code | 触发条件 | 处理方式 |
|---|---|---|---|
| 429 | rate_limited | 超出每分钟请求数、每分钟 token 数或并发请求数;上游厂商限流;达到套餐每日配额上限。见 HTTP 429 的来源 | 有 Retry-After 时按其等待,否则指数退避 |
| 429 | upstream_saturated | 上游线路的名额已满,排队未成功;details 带 queue_position 与 queue_length | 按 Retry-After 退避,或更换模型 |
| 502 | upstream_error | 上游返回 5xx;上游拒绝平台的凭证或找不到模型;响应无法解析;流意外中断(details.provider_error.code 为 stream_interrupted) | 指数退避 |
| 503 | model_unavailable | 线路暂时都无法接收请求(熔断、限额、并发已满),或模型的全站并发已满。details.reason 为 endpoints_busy 或 model_busy,带 Retry-After | 按 Retry-After 等待。不带 Retry-After 的 503 见不可重试的错误 |
| 504 | upstream_timeout | 上游超时。details.timeout 取 connect、first_byte、idle、response(非流式等待完整响应)、total 或 upstream | 指数退避;持续出现时调小 max_tokens 或改用流式 |
| 409 | idempotency_conflict | 请求带 Idempotency-Key,同一个键的请求仍在处理中 | 等待后重试,并设次数上限。同一 code 的另一种含义见不可重试的错误 |
| 500 | internal | 服务内部错误 | 指数退避;反复出现时提供 request_id 报障 |
不可重试的错误
#重试不改变结果,须先修改请求或设置。
| 状态码 | code | 触发条件 | 处理方式 |
|---|---|---|---|
| 400 | validation_failed | 请求不合法,或上游拒绝请求而平台未识别其语义。具体情况见表下 | 按 message 与 param 修改请求 |
| 400 | context_window_exceeded | 输入(或输入加 max_tokens)超出模型的上下文窗口。param 为 messages,code 为 context_length_exceeded;两种来源见表下 | 缩短输入、调小 max_tokens,或换用窗口更大的模型,见参数如何被处理「上下文窗口」 |
| 400 | unsupported_param | 参数或内容无法带到线路上,或远程图片无法取回。具体情况见表下 | 去掉 param 所指的参数或内容,或更换模型,见参数如何被处理 |
| 400 | content_filtered | 上游内容审核拒绝。details.semantic 为 content_filtered,code 为 content_filter;图片接口上 code 为 OpenAI 图片接口的 moderation_blocked | 修改内容。各厂商审核标准不同,更换模型不一定有效 |
| 400 | unsupported_protocol | 模型所在线路的入口不支持该操作。目前只有一种情况:调用向量接口,而线路只有 Anthropic 入口(向量只走 openai、custom、gemini 入口,见多厂商差异) | 更换模型 |
| 401 | unauthenticated | 未带 Key、Key 格式错误(常见原因是填入了其他厂商的 Key)或 Key 不存在 | 不自动重试。检查环境变量,值应为以 sk-sr- 开头的 SciRouter Key |
| 401 | key_revoked / key_expired | Key 已吊销或已过期 | 在控制台更换 Key |
| 401 | account_suspended | 账号已停用 | 联系平台 |
| 402 | insufficient_quota | 余额不足以预扣(按输入估算加输出上限预扣,充值余额大于 0 的账户输出只按预留估,见认证与 API Key「预扣」),或此前结算使配额变为负数;带 details.required_quota,团队账户另带 details.account_kind: "team" | 充值(团队账户联系负责人)。max_tokens 小于平台设定的输出预留时,调小它可减少预扣 |
| 403 | model_not_allowed | 模型不在白名单中;details.scope 为 key、project 或 plan | 修改白名单、更换 Key 或更换模型 |
| 403 | model_restricted | 受限模型,本次调用所在的工作区未获授权 | 使用已获授权的团队项目下的 Key |
| 403 | team_suspended | Key 属于团队项目,该团队已停用 | 联系团队负责人 |
| 404 | model_not_found | 模型 id 不存在,或是对调用方不可见的受限模型 | 检查 id(区分大小写),以 GET /models 的返回为准 |
| 404 | project_not_found / team_not_found | 前者:Key 所属项目已不存在;后者:Key 的所有者已不在该团队 | 更换 Key |
| 409 | idempotency_conflict | 同一个 Idempotency-Key 用于不同的请求体,通常是代码复用错了键 | 检查键的生成与复用。该 code 与「处理中」的 409 相同,仅 message 不同;有限次重试后仍返回 409 时按本行处理 |
| 409 | idempotency_conflict(details.reason = result_not_replayable) | 图片接口不保存 b64_json 与流式结果:同一个键的请求已完成,无法重放 | 需要重新生成时使用新的键 |
| 413 | payload_too_large | 请求体超过上限(默认 4 MB) | 拆分后再发送 |
| 422 | project_archived | Key 所属项目已归档 | 使用不属于该项目的 Key |
| 429 | key_quota_exceeded | 该 Key 的月度上限不足(已用量加本次估算超过上限);不带 Retry-After | 下月恢复。上限创建后不可修改,急需时更换 Key |
| 429 | project_budget_exceeded | 项目的月预算已用完;Retry-After 指向下月 1 日 | 在控制台调高项目预算 |
| 503 | model_unavailable | 本次请求在该模型上无法完成(如带 tools 而没有支持工具调用的线路、超过单次上限),或模型已下线、维护中、尚未定价。不带 Retry-After,带响应头 x-should-retry: false;details.reason 见 HTTP 503 的 details.reason | 重试无效。按 details.reason 修改请求或更换模型 |
validation_failed 的触发条件:
- 请求体不是 JSON 对象、字段类型错误、缺少
model、messages为空、stop类型错误; max_tokens超过模型或套餐的单次上限(details.limit);- 输入的 token 估算超过套餐的每分钟上限:
details.reason为plan_tpm_exceeded,见 HTTP 400 的 details.reason; metadata、托管工具声明或缓存相关请求头写法错误;Idempotency-Key超长;- 上游拒绝请求,而平台未识别是哪种语义:
details.source为upstream,带provider_error。已识别语义的归入context_window_exceeded、unsupported_param、content_filtered。
context_window_exceeded 的两种来源:
- 平台发出前估算得出:带
details.limit、details.estimated、details.max_tokens; - 上游报告:
details.semantic为context_window_exceeded,厂商文案含数字时才带limit与estimated。
unsupported_param 的触发条件:
- 契约类参数在该模型的所有线路上都无法带到(
details.param、details.cause); - 上游明确拒绝某个参数,而平台无法去掉它(
details.semantic为unsupported_param,code为unsupported_parameter或unsupported_value); - 请求含只能原样转发的内容,而没有可转发的线路(
details.reason为unsupported_content,details.unsupported_content列出这些内容); - 远程图片无法取回(
details.reason为media_fetch_failed)。
type 与状态码
#type 按状态码映射,与 OpenAI 的惯例一致。程序分支使用 code。
type | 状态码 |
|---|---|
authentication_error | 401 |
insufficient_quota | 402 |
permission_error | 403 |
rate_limit_error | 429 |
upstream_error | 502、503、504 |
server_error | 其他 5xx |
invalid_request_error | 其他 4xx |
上游语义错误
#平台将上游错误中的三种常见语义归为固定的 code:context_window_exceeded(上下文超长)、unsupported_param(参数不支持)、content_filtered(内容审核)。三者均为 400,不可重试,须修改请求。错误体分两层:
平台码(scirouter_code) | OpenAI 格式的 error.code | Anthropic 格式的 message |
|---|---|---|
CONTEXT_WINDOW_EXCEEDED | context_length_exceeded,param 为 messages,message 以 This model's maximum context length is {limit} tokens. However, … 开头 | 输入本身超出时含 prompt is too long: {estimated} tokens > {limit} maximum;输入未超出、加上 max_tokens 后超出时含 input length and `max_tokens` exceed context limit: {estimated} + {max_tokens} > {limit};上游报告且无法提取数字时只有 prompt is too long |
UNSUPPORTED_PARAM | unsupported_parameter(取值不支持时为 unsupported_value),param 为参数名 | 写明参数名与原因 |
CONTENT_FILTERED | content_filter | — |
- 平台码在
error.scirouter_code(OpenAI 格式)或error.code(Anthropic 格式,小写)中;details照常带param、limit、estimated、semantic、provider_error。 code只取原厂可识别的值,供现有客户端使用:Claude Code 按prompt is too long中的两个数字裁剪历史、按exceed context limit调小max_tokens;Codex 仅在response.failed中出现context_length_exceeded时压缩对话;不少 OpenAI 兼容客户端按context_length_exceeded或unsupported_parameter分支。- 无法带到线路上的提示类参数默认由网关去掉并留痕,不返回 400,见参数如何被处理。
- 上下文超长通常由平台在发出前估算得出(带
details.estimated),此时不预扣、不占名额。 - 上游不支持某个参数时,平台先尝试去掉该参数后重发(响应头
X-SciRouter-Param-Actions中记为healed)。返回 400 表示该参数无法去掉,或没有可换的线路。
Anthropic 格式的错误体
#/messages 与 /messages/count_tokens(以及带 anthropic-version 请求头的 /models)返回 Anthropic 格式的错误体,鉴权失败时也是如此,Anthropic SDK 可直接识别:
json{
"type": "error",
"error": {
"type": "overloaded_error",
"message": "…",
"code": "model_unavailable",
"details": { "reason": "endpoints_busy" }
},
"request_id": "req_88a1"
}状态码、code 与 details 与可重试的错误、不可重试的错误两张表完全相同(error.code、error.details 为扩展字段),request_id 位于顶层。error.type 按状态码映射,平台策略类拒绝例外,取 policy_blocked:
error.type | 状态码 |
|---|---|
invalid_request_error | 400,以及 422 等其余 4xx |
authentication_error | 401 |
billing_error | 402 |
permission_error | 403 |
not_found_error | 404 |
conflict_error | 409 |
request_too_large | 413 |
rate_limit_error | 429 |
api_error | 500、502,以及不带 Retry-After 的 503(本次请求在该模型上无法完成) |
overloaded_error | 带 Retry-After 的 503(线路或模型暂时繁忙) |
timeout_error | 504 |
policy_blocked | 平台策略类拒绝,不按状态码映射,见下表 |
policy_blocked 覆盖下列 code。状态码保持各自的 401、402、403、404、422 或 429,并带 x-should-retry: false。修改请求或重试均无效,需人工处理;Claude Code 直接展示该错误,不重试。
| 类别 | code |
|---|---|
| 配额 | insufficient_quota、key_quota_exceeded、project_budget_exceeded |
| 权限与受限模型 | model_not_allowed、model_restricted |
| Key、账号、团队、项目的状态 | key_revoked、key_expired、account_suspended、team_suspended、project_not_found、project_archived |
模型暂时不可用时仍返回 503,不使用 Anthropic 的 529。Anthropic SDK 对 5xx 自动重试,带 x-should-retry: false 的除外。程序分支使用 error.code。
以下两项遵循 Claude Code 的网关约定:
- 能力类拒绝带固定标记:平台自身拒绝、且客户端关闭对应能力即可恢复的 400,在
message末尾追加capability_rejected: <class>,details.capability_rejected取相同值。Claude Code 收到后关闭该能力并重发。class 取值见下表。 - 转发上游的 4xx 时,厂商原文保留在
message中(前缀为「上游拒绝了请求:」),按子串匹配的客户端不受影响。
| class | 含义 |
|---|---|
prompt_too_long | 输入超出窗口;或输入估算超过套餐每分钟 token 数(details.reason 为 plan_tpm_exceeded),此时 message 同样以 prompt is too long: N tokens > M maximum 开头,M 为套餐每分钟上限 |
max_tokens_context_overflow | 输入加 max_tokens 超出窗口 |
thinking_signature | 思考块的签名被拒 |
structured_outputs_unsupported | 结构化输出(response_format)被拒 |
effort_unsupported | 思考参数被拒 |
image_block | 图片输入被拒 |
document_block | 文件输入被拒 |
HTTP 503 的 details.reason
#model_unavailable 同时覆盖「暂时繁忙」与「本次请求在该模型上无法完成」两类情况,以 details.reason 区分。details.reason 为固定的英文码,可用于程序分支。
| reason | 含义 | 带 Retry-After | 处理方式 |
|---|---|---|---|
endpoints_busy | 该模型的线路暂时都无法接收请求(熔断、限额或并发已满) | 是 | 按 Retry-After 等待 |
model_busy | 该模型在平台上的并发请求数已满 | 是 | 按 Retry-After 等待 |
tools_unsupported | 请求带 tools,而该模型没有支持工具调用的线路 | 否 | 去掉 tools,或更换模型 |
streaming_unsupported | 请求为流式,而该模型没有支持流式的线路 | 否 | 改用非流式,或更换模型 |
input_too_large | 预计 token 数(输入加 max_tokens)超过线路的单次上限 | 否 | 缩短输入、调小 max_tokens |
no_capable_endpoint | 没有一条线路同时满足本次请求的要求(工具调用、流式、长度) | 否 | 更换模型 |
no_endpoint | 该模型当前没有可用的线路 | 否 | 更换模型,稍后再查看模型状态 |
model_offline | 模型已下线、维护中或尚未定价 | 否 | 更换模型,稍后再查看模型状态 |
不带 Retry-After 的 503 重试无效。 这类响应带 x-should-retry: false。OpenAI 与 Anthropic 的官方 SDK 以及 Claude Code 先读取该响应头,值为 false 时停止自动重试并直接返回错误;自行实现的重试逻辑也应读取该响应头。
请求含只能原样转发的内容、而没有可转发的线路时,返回 400 unsupported_param(details.reason 为 unsupported_content),不再归入 no_capable_endpoint。503 只用于等待后可恢复或更换模型可解决的情况。
HTTP 400 的 details.reason
#validation_failed 多数情况下不带 details.reason,按 message 与 param 处理即可。下列情况带固定的 reason,适用的接口见各行:
| reason | 含义 | 处理方式 |
|---|---|---|
server_tool_unsupported | /messages 或 /responses 的请求使用了厂商的服务端工具或连接器(web_search_*、web_fetch_*、code_execution_*、mcp_servers、container 等) | 去掉这些工具,改用自定义工具 |
price_param_unsupported | 请求带了会使厂商按另一档单价收费的参数(details.params 列出),而平台未上架对应的模型变体 | 去掉这些参数,或改用变体,见 Messages |
sub_model_unpriced | /messages 的 advisor 工具或 fallbacks 列表引用的模型未在平台上架或未定价(param 指向该字段)。无权调用该模型时,与直接调用它一样返回 403 | 换成平台上已定价的模型(正名或别名),见 Messages「计费」 |
stateful_unsupported | /responses 带了 previous_response_id、conversation、prompt 或 item_reference。平台不保存响应,没有可引用的状态 | 将完整的对话历史放入 input,见 Responses |
background_unsupported | /responses 带了 background: true | 去掉该参数,改为同步调用 |
plan_tpm_exceeded | 输入的 token 估算本身超过了套餐每分钟的 token 数,无论等多久都发不出去(param 为 messages;向量为 input)。Anthropic 格式的 message 以 prompt is too long: 开头并带 capability_rejected: prompt_too_long,Claude Code 据此尝试自动压缩对话后重发;对话太长、压缩请求本身也超过上限时,压缩会失败。details.limit 为套餐每分钟上限,details.estimated 为输入估算。max_tokens 不参与这一判定 | 缩短输入(如压缩对话历史),或升级套餐 |
model_kind_mismatch | 模型种类与接口不符:对话类接口(/chat/completions、/responses、/messages、/embeddings)调用了生图等媒体模型,或图片接口调用了非生图模型(此前对话接口调用生图模型返回 503) | 按 /models 的 scirouter.kind 调用对应的接口 |
edit_unsupported / variations_unsupported | 该生图模型不支持改图或不支持变体(见 scirouter.image.edit 与 variations) | 更换模型 |
size_multiple_of、size_ratio、size_max_edge、size_min_pixels、size_max_pixels、size_not_preset、size_auto_not_allowed、size_format | 图片的 size 不符合模型 scirouter.image.sizes 的规则 | 按 sizes 修改尺寸 |
unsupported_param 与 context_window_exceeded 的 details.reason 同样固定:
| reason | code | 含义 | 处理方式 |
|---|---|---|---|
unsupported_param | unsupported_param | 契约类参数无法带到线路上:details.param 为参数名,details.cause 为原因,取值见下表 | 去掉该参数,或更换模型 |
unsupported_content | unsupported_param | 请求含只能原样转发的内容(Anthropic 格式的 search_result、按需压缩、advisor 工具等;Responses 的 input_file、厂商定义的客户端工具等),details.unsupported_content 列出这些内容,而该模型没有可原样转发的线路 | 去掉这些内容,或更换模型 |
media_fetch_failed | unsupported_param | 平台无法取回远程图片(非公网地址、过大、超时、数量过多) | 改为 data URL 内联,或更换地址 |
context_window | context_window_exceeded | 平台发出前估算出输入(加 max_tokens)超出窗口;details.scope 为 endpoint 时为线路级窗口 | 缩短输入、调小 max_tokens |
details.cause | 含义 |
|---|---|
feature_missing | 模型未声明对应能力 |
rule_unsupported | 模型的请求规则不接受该参数 |
not_carried | 所有线路都无法带到,details.params 列出全部这类参数 |
strict | 调用方通过请求头要求严格处理,见参数如何被处理 |
HTTP 429 的来源
#rate_limited 与另外两个配额类 code 的区别:
| code | 来源 | details | Retry-After |
|---|---|---|---|
rate_limited | 每分钟请求数、每分钟 token 数或并发请求数超限 | scope:personal(账号)、key(该 Key)或 team(团队项目下的 Key 按团队限额计,成员共用) | 通常为秒级 |
rate_limited | 套餐每日配额上限;message 为「今日用量已达套餐上限」 | limit_quota、spent_quota | 指向次日零点(平台时区) |
key_quota_exceeded | Key 的月度上限 | — | 不带;下月恢复 |
project_budget_exceeded | 项目的月预算 | — | 指向下月 1 日 |
每分钟 token 数在请求开始时按「输入估算 + 输出预留」计入,输出预留是 max_tokens 与平台设定值中的较小者;请求结束后按实际用量多退少补,实际输出超过预留的部分补记。因此 max_tokens 写得大不会被提前拒绝,但同一分钟里的长输出会让后续请求收到 429。
按 code 与 details 分支,不只看状态码。等待时长以 Retry-After(或 details.retry_after_seconds)为准。
重试策略
#网关内置故障转移:默认在上游超时、返回 5xx 或被上游限流时,自动转到该模型的下一条可用线路,最多再转 2 次,总耗时不超过 60 秒(各模型可单独配置)。只有一条线路的模型、已开始输出的流式请求不做转移。
因此调用方收到 5xx 时,网关通常已尝试过其他线路;尝试次数见成功响应中的 scirouter.attempts 或响应头 X-SciRouter-Attempts。客户端的重试使用指数退避,不立即重发。
非流式请求重试时带同一个 Idempotency-Key,首次请求实际已成功时不会重复扣费。前提是首次请求未被客户端先断开:客户端断开的请求由服务端取消且不保存结果,见缓存与幂等。
官方 SDK 默认自动重试 429 与 5xx,不区分 code,见 SDK 与框架「重试与超时」。
流式响应中的错误
#流式响应可能在已输出部分内容之后出错。此时 HTTP 状态码已是 200,错误以带 error 字段的分片出现在流中,随后流直接结束,不再发送 data: [DONE]:
textdata: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"这段序列的"}}]}
data: {"error":{"message":"上游模型服务响应超时","type":"upstream_error","code":"upstream_timeout","request_id":"req_88a1","details":{"timeout":"idle"}}}只检查 HTTP 状态码会把截断的回答当作完整回答。三种格式的流式结束标志与出错方式:
| 接口 | 正常结束 | 输出开始后出错 |
|---|---|---|
对话补全(/chat/completions) | data: [DONE] | 带 error 字段的分片,之后没有 [DONE] |
/messages(Anthropic 格式) | message_stop 事件,没有 [DONE] | event: error 事件,内容为 Anthropic 格式的错误体,随后断开 |
/responses | response.completed 或 response.incomplete 事件,之后一行 [DONE] | event: response.failed 事件,response.error 带 code 与 message |
未收到正常结束标志即结束的流,一律按失败处理。
上下文超长例外:/responses 的流式调用无论在开流前还是开流后判定超长,均返回 HTTP 200 与 response.failed 事件(response.error.code 为 context_length_exceeded),Codex 只在收到该事件时压缩对话。非流式调用仍返回 HTTP 400。
流中错误帧的 code 只取原厂可识别的值,平台码仍在 scirouter_code:
流中的 code | 对应情况 |
|---|---|
rate_limit_exceeded | 限流与上游满载 |
insufficient_quota | 配额类错误 |
server_is_overloaded | 带 Retry-After 的 503 |
server_error | 其余 5xx |
context_length_exceeded 等 | 上游语义错误,见上游语义错误 |
未知路径
#请求 /v1 下不存在的路径(如 /v1/completions)时返回 404,错误体为站内接口的格式(大写的 NOT_FOUND),与本页其他错误体不同。官方 SDK 同样抛出「未找到」异常。出现该错误时检查请求路径与 base_url,确认没有多写或少写一段 /v1。