# 常见错误

https://modelportal.ai/docs/errors?lang=zh

出错时先看 HTTP 状态码和错误码，再按下表处理。错误信息的语言跟随请求头 `Accept-Language`（`zh-CN` 或 `en-US`）。

## 错误格式

| 接口 | 格式 |
| --- | --- |
| OpenAI 兼容 `/v1/*` | `{"error": {"message", "type", "code", "request_id"}}` |
| Anthropic 兼容 | `{"type": "error", "error": {"type", "message"}}`，没有机器可读的错误码 |
| Gemini 兼容 | `{"error": {"code", "message", "status"}}`，`code` 是 HTTP 状态码，没有平台错误码 |
| 平台接口 `/api/v1/*`、媒体任务 | `{"code", "message", "request_id", "details"}` |

联系支持时请附上 `request_id`。调用已经发往上游时，响应头 `X-ModelPortal-Request-Id` 是这次调用的请求 ID，能在控制台的调用明细里按它查到。

## 错误码

| 错误码 | HTTP | 原因 | 处理 |
| --- | --- | --- | --- |
| `invalid_request` | 400 | 请求体或参数不合法，包括 `provider` 里的未知字段和不存在的供应商标识、报价标识；错误信息会指出字段 | 按提示修正请求 |
| `unsupported_parameter` | 400 | 请求里的参数或能力没有任何候选报价支持，包括不能关闭思考的模型；错误信息列出参数名 | 去掉该参数，或换用支持的模型 |
| `stateful_not_supported` | 400 | `/v1/responses` 带了 `previous_response_id`、`conversation` 或 `background`，平台暂不支持有状态会话 | 自己保存上下文，每次带完整输入 |
| `invalid_grant` | 400 | 应用授权码无效、过期、已用过，或已不满足创建密钥的条件 | 重新发起授权 |
| `invalid_api_key` | 401 | 密钥缺失、写错或已撤销；或在 OpenAI、Anthropic 接口里把密钥放在了 URL 参数里 | 检查密钥和请求头 |
| `key_inactive` | 401 | 密钥已暂停或已过期，或所属应用已停用 | 恢复密钥，或新建一把 |
| `insufficient_balance` | 402 | 余额不足以覆盖这次调用的预估费用，或账户欠费 | 充值 |
| `budget_exceeded` | 402 | 达到密钥的每日或每月消费上限 | 调高上限或等待周期切换 |
| `key_restricted` | 403 | 模型不在这把密钥的可用模型里，来源 IP 不在密钥的白名单里，或这类密钥不能访问该接口 | 修改密钥的可用模型或 IP 白名单 |
| `request_blocked` | 403 | 请求被风控拦截，或账户被冻结、暂停 API 调用、封禁。内容命中内容规则、或请求带图片而图片审核暂时不可用时也是这个码，错误信息末尾写着命中的类别，如 `content.prohibited.violence`、`content.moderation_unavailable` | 查看站内通知或提交工单；内容被拦截时修改内容，有异议可以申诉 |
| `region_restricted` | 403 | 请求来自暂不支持访问的地区 | 该地区暂时无法使用，如有疑问请提交工单 |
| `verification_required` | 403 | 需要先完成身份验证 | 在控制台完成验证 |
| `model_not_found` | 404 | 模型不存在、维护中，或不具备这个接口需要的能力 | 核对模型 ID 与[模型能力](/docs/capabilities) |
| `model_retired` | 410 | 模型已下架，配置了替代模型时错误信息会写明 | 改用替代模型 |
| `no_eligible_endpoint` | 422 | 没有满足约束的报价，错误体附 `excluded` 列表 | 按下方排除原因调整约束，或稍后重试 |
| `rate_limited` | 429 | 触发账户或密钥的每分钟请求数或同时进行的请求数上限，带 `Retry-After` | 退避后重试，或等待进行中的请求结束 |
| `capacity_exhausted` | 429 | 候选报价全部满载（达到声明的限额，或在上游 429 后的短冷却中），或者每次尝试都收到上游 429，带 `Retry-After` | 按 `Retry-After` 等待后重试 |
| `upstream_failed` | 502 | 允许的尝试都失败了，而且不全是上游 429，错误体附 `attempts` | 稍后重试，失败的调用不收费 |

下面几个错误码不在上表的规范码里，也可能出现：

| 错误码 | HTTP | 原因 | 处理 |
| --- | --- | --- | --- |
| `request.too_large` | 413 | 请求体超过大小上限 | 缩小请求体，大文件先上传 |
| `request.endpoint_moved` | 410 | 用了已停用的旧地址，如 `/anthropic/*` 下的地址 | 按错误信息改用新地址 |
| `upstream.unavailable` | 503 | 平台依赖的服务（如限流服务）暂时不可用 | 稍后重试 |

## 失败的尝试

`upstream_failed` 和因上游 429 返回的 `capacity_exhausted` 在错误对象里带 `attempts`，按顺序列出每次尝试：

```json
{"attempts": [{"provider": "PROVIDER_ID", "endpoint": "ENDPOINT_ID", "status": 503, "cost": 0.000000}]}
```

`provider` 是供应商标识，`endpoint` 是报价标识，`status` 是上游的 HTTP 状态（连接失败或超时时为 0），失败的尝试 `cost` 为 0。每次尝试都收到上游 429 时返回 429 `capacity_exhausted`，`Retry-After` 取各次尝试里最早能恢复的时间：上游给了 `Retry-After` 就用上游的值，没给就按短冷却结束的时间算。

## 422 的排除原因

`no_eligible_endpoint` 的错误体带 `excluded` 列表，逐个列出通过了你的约束、但被排除的报价和原因代码：

```json
{"excluded": [{"offering_id": "route_xxxxxxxx", "reason": "unavailable"}]}
```

| 原因代码 | 含义 |
| --- | --- |
| `unavailable` | 供应商未上线、接入点未就绪，或报价不是「可用」或「降级」状态（如暂停、维护中） |
| `region` | 报价禁止服务请求来源地区 |
| `capability` | 报价不支持请求用到的能力或参数 |
| `context` | 预估输入（加上你传的输出上限）超过报价的上下文长度 |
| `circuit_open` | 报价处于熔断冷却或半开状态 |
| `upstream_cooldown` | 报价在上游返回 429 后的短冷却中 |
| `capacity` | 当前 60 秒窗口内已达报价声明的 RPM 或 TPM |
| `session` | 请求带了上游签名的 thinking 块，只能由产生签名的报价承接，而它不可用 |

如果你的约束（`only`、`ignore`、`data_collection`、`quantizations`、`max_price`、`data_regions`、`exclude_regions`）一开始就排除了全部报价，`excluded` 为空数组，错误信息说明是哪些约束。从未公开展示过的报价不会列出。

两种例外：只因参数或能力不支持而没有报价时返回 400 `unsupported_parameter`；只因满载或上游 429 冷却而没有报价时返回 429 `capacity_exhausted`，`Retry-After` 是最早恢复的时间。

## 限流

每个账户有三项限额：账户每分钟请求数、单个 Key 每分钟请求数、同时进行的请求数。默认值随账户累计充值分档提高：

| 累计充值 | 账户每分钟请求数 | 单个 Key 每分钟请求数 | 同时进行的请求数 |
| --- | --- | --- | --- |
| 0 起 | 600 | 600 | 5 |
| 50 USD 起 | 1,200 | 1,200 | 10 |
| 500 USD 起 | 3,000 | 3,000 | 30 |

任一项超限都返回 429 `rate_limited`，响应头 `Retry-After` 是建议等待的秒数。账户当前的限额在控制台的 API 密钥页查看，需要更高的限额请提交工单。

## 重试建议

- 429、502 和 503 可以重试，建议指数退避并设置最大次数。
- 400、401、402、403、404、410、422 重试不会成功，需要先按上表处理。
- 首个内容事件之前，所有尝试共用 600 秒总超时；开始输出后，两个事件之间超过 120 秒没有数据会断开。长输出建议使用流式。

## 常见问题

### 返回 429 应该怎么重试？

rate_limited 可以重试，速率超限与并发超限都返回它，建议指数退避并设置最大重试次数，同时减少并发请求。

### upstream_failed 会扣费吗？

不会。上游出错或超时的调用按失败处理，不收费，可以稍后重试。

### Anthropic 格式为什么看不到错误码？

Anthropic 协议的错误体只有类型和信息，没有机器可读的错误码；需要精确判断时可以改用 OpenAI 兼容接口。

