---
title: "错误码"
description: "pirouter API 的错误按 error.code 处理：每个错误码对应的 HTTP 状态码、含义、处理办法和要不要重试，以及没有错误码的 502、413、503 和 provider 原样转发的错误。"
canonical: "https://pirouter.ai/zh/docs/api/errors"
last-updated: "2026-10-17"
lang: "zh"
source: "content/docs/zh/api/errors.mdx"
---

# 错误码

pirouter API 的错误按 error.code 处理：每个错误码对应的 HTTP 状态码、含义、处理办法和要不要重试，以及没有错误码的 502、413、503 和 provider 原样转发的错误。

请求失败时，代码里按响应体的 `error.code` 处理：它说明具体是哪一种失败，比 HTTP 状态码更细，而且不会改。`400`、`401`、`404`、`413`、`422` 重试没有用，`402` 先充值，`429` 等 `Retry-After`，`5xx` 逐步加长间隔重试。

## 错误体

三种协议的推理端点返回同一种错误格式：

```json
{
  "error": {
    "message": "No such model. Model names are vendor-qualified (vendor/model), so a name copied from a provider's own docs needs its vendor prefix added. Call GET /v1/models for the slugs this gateway serves.",
    "type": "not_found_error",
    "code": "model_not_found"
  }
}
```

`error.code` 是稳定的字符串，代码里按它判断。`error.message` 是写给人看的，措辞可能调整，不要匹配它的文字。

每个响应都带 `X-Pi-Trace-Id` 响应头，错误响应也一样。反馈问题时附上它的值。

模型目录端点的错误体更短，见 [API 概览](https://pirouter.ai/zh/docs/api.md#错误)。

## 错误码一览

| HTTP  | `error.code`                                                                                   | 含义                            | 处理                                     |
| ----- | ---------------------------------------------------------------------------------------------- | ----------------------------- | -------------------------------------- |
| `400` | [`invalid_request`](https://pirouter.ai/zh/docs/api/errors.md#invalid_request)                 | 请求体缺少必填字段。                    | 补上缺少的字段。原样重试无效。                        |
| `400` | [`context_length_exceeded`](https://pirouter.ai/zh/docs/api/errors.md#context_length_exceeded) | 输入明显超出了模型的上下文上限。              | 缩短输入，或换上下文更大的模型。原样重试无效。                |
| `401` | [`invalid_api_key`](https://pirouter.ai/zh/docs/api/errors.md#invalid_api_key)                 | 没有带 key，或者值不是 pirouter 的 key。 | 检查 key 所在的请求头和环境变量。不要重试。               |
| `401` | [`api_key_not_found`](https://pirouter.ai/zh/docs/api/errors.md#api_key_not_found)             | key 的格式正确，但不存在这个 key。         | 检查 key 是否复制完整。不要重试。                    |
| `401` | [`api_key_revoked`](https://pirouter.ai/zh/docs/api/errors.md#api_key_revoked)                 | key 已被吊销。                     | 到控制台新建一个 key。不要重试。                     |
| `401` | [`api_key_expired`](https://pirouter.ai/zh/docs/api/errors.md#api_key_expired)                 | key 已过有效期。                    | 到控制台新建一个 key。不要重试。                     |
| `402` | [`insufficient_balance`](https://pirouter.ai/zh/docs/api/errors.md#insufficient_balance)       | 钱包余额不够支付这次请求。                 | 充值后再发送。不要自动重试。                         |
| `404` | [`model_not_found`](https://pirouter.ai/zh/docs/api/errors.md#model_not_found)                 | 模型 ID 不存在或未启用。                | 改正模型 ID，用 GET /v1/models 查可用的 ID。不要重试。 |
| `404` | [`no_eligible_provider`](https://pirouter.ai/zh/docs/api/errors.md#no_eligible_provider)       | 路由设置把这个模型的 provider 全部排除了。    | 放宽 provider 字段或路由设置。原样重试无效。            |
| `422` | [`validation_failed`](https://pirouter.ai/zh/docs/api/errors.md#validation_failed)             | 请求违反了规则：模型不在这个端点上提供，或路由字段写错。  | 按 message 指出的问题改正。原样重试无效。              |
| `429` | [`rate_limited`](https://pirouter.ai/zh/docs/api/errors.md#rate_limited)                       | 请求速度超过了限流允许的范围。               | 等 Retry-After 给出的秒数后重试。                |
| `500` | [`internal_error`](https://pirouter.ai/zh/docs/api/errors.md#internal_error)                   | pirouter 一侧的意外故障。             | 重试，每次等待逐步加长。                           |
| `503` | [`provider_unavailable`](https://pirouter.ai/zh/docs/api/errors.md#provider_unavailable)       | 当前没有健康的 provider 能提供这个模型。     | 重试，每次等待逐步加长；或写上备用模型。                   |

下面每个错误码一节：先说含义，再说怎么处理、要不要重试。

### `invalid_request`

请求体缺少所用协议要求的字段。目前指的是模型：请求体里既没有 `model` 也没有 `models` 时返回 `400`，`message` 是 `model is required`。调用 pirouter 不提供的端点（例如 `POST /v1/embeddings`）也返回这个错误，各协议页的「目前没有的能力」列出了这些端点。

补上字段，或改用 pirouter 提供的端点。原样重试没有用。

### `context_length_exceeded`

输入明显超出了所有能提供这个模型的 provider 的上下文上限，pirouter 在转发之前就拒绝了这次请求，不计费。`message` 里写着估算的输入大小和上限。这个大小是估算值，所以只拒绝明显超出的请求：接近上限的请求照常转发，由 provider 决定。

缩短输入，或者换一个上下文更大的模型。原样重试会得到同样的错误。

### `invalid_api_key`

没有带 key，或者值不是以 `sk-pi-` 开头。

检查 key 放在哪个请求头里、环境变量有没有设置。网关读哪些请求头见[在请求里带上 key](https://pirouter.ai/zh/docs/authentication.md#在请求里带上-key)。改好之前重试没有用。

### `api_key_not_found`

值的格式像 pirouter 的 key，但这个 key 不存在。检查 key 有没有复制完整。改好之前重试没有用。

### `api_key_revoked`

key 已被吊销。吊销不可恢复，到控制台新建一个 key。

### `api_key_expired`

key 已过创建时选定的有效期。到控制台新建一个 key。

### `insufficient_balance`

钱包余额不够支付这次请求的预估费用。先[充值](https://pirouter.ai/zh/docs/guides/billing.md#充值)，再重新发送。细节见[余额不足](https://pirouter.ai/zh/docs/guides/billing.md#余额不足)。

> **注意：** 不要在代码里自动重试 `402`：余额不变，结果就一直是 `402`。

### `model_not_found`

模型 ID 不存在或未启用。模型 ID 的写法是 `vendor/model`，从厂商自己的文档里抄来的名字要补上厂商前缀。`GET /v1/models` 列出可以调用的 ID，见[模型 ID](https://pirouter.ai/zh/docs/models.md#模型-id)。

已下线的模型同样返回 `404` 和这个错误码，`message` 写明它的下线日期和去哪里换一个模型。用别名调用它，或在 `models` 里把它写成回退模型，返回的也是这个错误。

改用一个可用的模型 ID。原样重试没有用。

### `no_eligible_provider`

模型存在，但请求里的 `provider` 字段加上工作区的路由设置，把提供它的 provider 全部排除了。

重试没有用，要改设置：响应体的 `error.metadata` 列出了提供这个模型的 provider，以及是哪一步排除了最后一个。见[没有可用的 provider 时](https://pirouter.ai/zh/docs/guides/routing.md#没有可用的-provider-时)。

### `validation_failed`

请求能读懂，但违反了规则。原因有两种，`message` 会说明是哪一种：

- 模型不在你调用的端点上提供。`message` 会列出它在哪些端点上提供。见[协议不匹配](https://pirouter.ai/zh/docs/models.md#协议不匹配)。
- 路由字段（`provider`、`models`、`route`、`preset`）写错了。`message` 会点名字段。见[写错了会怎样](https://pirouter.ai/zh/docs/guides/routing.md#写错了会怎样)。

按 `message` 改请求。原样重试没有用。

### `rate_limited`

请求速度超过了限流允许的范围。响应带 `Retry-After` 响应头，值是 1 到 60 之间的秒数。

等这么久之后再重试，并减少同时在途的请求数。限流的对象是这次请求被选中的部署，不是你的 key，所以换 key 没有用。限流怎么计见[限流](https://pirouter.ai/zh/docs/api/rate-limits.md)。

### `internal_error`

pirouter 一侧出了故障。稍等后重试。持续出现时，附上一次失败请求的 `X-Pi-Trace-Id` 反馈给我们。

### `provider_unavailable`

当前没有健康的 provider 能提供这个模型。稍等后重试。想在某个模型不可用时照常得到回复，在请求里写上[回退模型](https://pirouter.ai/zh/docs/guides/fallbacks.md)。

provider 拒绝了 pirouter 自己的凭证（provider 返回 `401` 或 `403`，不是你的 key 的问题）、而且其他 provider 也没能接替时，返回的也是这个 `503` 和错误码。这个响应带 `X-Pi-Provider` 和 `X-Pi-Model`，指出是哪个 provider 拒绝的。

## 没有错误码的错误

下面三种状态码不带 `error.code`，按状态码处理。

| HTTP 状态码 | 含义                                                                                                                          | 处理             |
| -------- | --------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `502`    | 网关没能和 provider 完成这次请求                                                                                                       | 稍等后重试          |
| `413`    | 请求体超过了端点接受的上限：[编辑图像](https://pirouter.ai/zh/docs/api/image-edits.md)为 32 MiB。`error.type` 是 `invalid_request_error`。不转发，不计费 | 换更小的文件，原样重试没有用 |
| `503`    | 网关没能核对这次请求的 key 和余额。`error.type` 是 `service_unavailable`                                                                    | 稍等后重试          |

> **注意：** 不要假定 `502` 的响应体是 JSON。先看状态码，再尝试解析响应体。

## provider 返回的错误

provider 自己返回的错误，pirouter 带着它原本的状态码和响应体原样转发，不改写成 pirouter 的错误体，所以响应体遵循你所调用端点的协议。只有 provider 返回过的响应带 `X-Pi-Provider` 响应头，网关自己产生的错误不带，看这个响应头就能区分两者。例外是[长请求](https://pirouter.ai/zh/docs/guides/timeouts.md#长请求)：无论哪种情况都不带 provider 相关的响应头。

有一种 provider 的错误不原样转发：provider 拒绝了 pirouter 自己的凭证时，你收到的是 pirouter 的错误体，状态码 `503`，错误码 [`provider_unavailable`](https://pirouter.ai/zh/docs/api/errors.md#provider_unavailable)，而不是 provider 的状态码和响应体。这个响应仍带 `X-Pi-Provider` 和 `X-Pi-Model`，但不带 `X-Pi-Upstream-Model`、`X-Pi-Upstream-Request-Id`，也不带 provider 自己的任何响应头。

你看到 provider 的 `429` 或 `5xx` 之前，pirouter 已经切换过这个模型的其他 provider。见[故障切换](https://pirouter.ai/zh/docs/guides/routing.md#故障切换)。

## 超时与长请求

等 provider 超过 600 秒仍未开始返回时，错误码是 `upstream_timeout`。provider 沉默超过 90 秒的请求以 `200` 开始，之后的错误写在响应体或流里。时限、保活与客户端该怎么设见[超时与长请求](https://pirouter.ai/zh/docs/guides/timeouts.md)。

## 哪些错误可以重试

| HTTP 状态码                               | 能否重试                                                                            |
| -------------------------------------- | ------------------------------------------------------------------------------- |
| `400`、`401`、`404`、`413`、`422`          | 不能。同样的请求会得到同样的错误，先改请求或 key                                                      |
| `402`                                  | 充值之后才行                                                                          |
| `429`                                  | 能，等 `Retry-After` 给出的秒数之后。见[限流](https://pirouter.ai/zh/docs/api/rate-limits.md) |
| `500`、`502`、`503`、`504`                | 能，每次重试之间的等待逐步加长                                                                 |
| `200`，但响应体里有 `error` 键，或流里有 `error` 事件 | 读 `error.code`，按对应的状态码处理。`upstream_timeout` 可以重试                                |

pirouter 在返回错误之前已经自己切换 provider 重试过，你的重试是第二道防线。两次重试之间隔几秒，不要隔几毫秒。

## 下一步

- [Provider 路由](https://pirouter.ai/zh/docs/guides/routing.md): 请求怎么选 provider，失败时怎么切换。
- [模型回退](https://pirouter.ai/zh/docs/guides/fallbacks.md): 请求的模型不可用时换到下一个模型。
