---
title: "错误码"
description: "pirouter API 返回的全部错误：错误体的格式，每个错误码对应的 HTTP 状态码和处理办法，超时，以及哪些错误值得重试。"
canonical: "https://pirouter.ai/zh/docs/errors"
last-updated: "2026-10-13"
lang: "zh"
source: "content/docs/zh/(start)/errors.mdx"
---

# 错误码

pirouter API 返回的全部错误：错误体的格式，每个错误码对应的 HTTP 状态码和处理办法，超时，以及哪些错误值得重试。

请求失败时，HTTP 状态码说明是哪一类失败，响应体里的 `error.code` 说明具体是哪一个。本页列出全部错误码和各自的处理办法。

## 错误体

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

```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/errors.md#invalid_request)           | 请求体缺少必填字段。                    |
| `401`    | [`invalid_api_key`](https://pirouter.ai/zh/docs/errors.md#invalid_api_key)           | 没有带 key，或者值不是 pirouter 的 key。 |
| `401`    | [`api_key_not_found`](https://pirouter.ai/zh/docs/errors.md#api_key_not_found)       | key 的格式正确，但不存在这把 key。         |
| `401`    | [`api_key_revoked`](https://pirouter.ai/zh/docs/errors.md#api_key_revoked)           | key 已被吊销。                     |
| `401`    | [`api_key_expired`](https://pirouter.ai/zh/docs/errors.md#api_key_expired)           | key 已过有效期。                    |
| `402`    | [`insufficient_balance`](https://pirouter.ai/zh/docs/errors.md#insufficient_balance) | 钱包余额不够支付这次请求。                 |
| `404`    | [`model_not_found`](https://pirouter.ai/zh/docs/errors.md#model_not_found)           | 模型 ID 不存在或未启用。                |
| `404`    | [`no_eligible_provider`](https://pirouter.ai/zh/docs/errors.md#no_eligible_provider) | 路由设置把这个模型的 provider 全部排除了。    |
| `422`    | [`validation_failed`](https://pirouter.ai/zh/docs/errors.md#validation_failed)       | 请求违反了规则：模型不在这个端点上提供，或路由字段写错。  |
| `429`    | [`rate_limited`](https://pirouter.ai/zh/docs/errors.md#rate_limited)                 | 请求速度超过了限流允许的范围。               |
| `500`    | [`internal_error`](https://pirouter.ai/zh/docs/errors.md#internal_error)             | pirouter 一侧的意外故障。             |
| `503`    | [`provider_unavailable`](https://pirouter.ai/zh/docs/errors.md#provider_unavailable) | 当前没有健康的 provider 能提供这个模型。     |

### `invalid_request`

请求体缺少所用协议要求的字段。目前指的是模型：请求体里既没有 `model` 也没有 `models` 时返回 `400`，`message` 是 `model is required`。补上字段后重新发送。

### `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 已被吊销。吊销不可恢复，到控制台新建一把。

### `api_key_expired`

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

### `insufficient_balance`

钱包余额不够支付这次请求的预估费用。先[充值](https://pirouter.ai/zh/docs/billing.md#充值)，再重新发送。不要在代码里自动重试：余额不变，结果就一直是 `402`。细节见[余额不足](https://pirouter.ai/zh/docs/billing.md#余额不足)。

### `model_not_found`

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

### `no_eligible_provider`

模型存在，但请求里的 `provider` 字段加上工作区的路由设置，把提供它的 provider 全部排除了。重试没有用，要改设置：响应体的 `error.metadata` 列出了提供这个模型的 provider，以及是哪一步排除了最后一家。见[一家都不剩时](https://pirouter.ai/zh/docs/routing.md#一家都不剩时)。

### `validation_failed`

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

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

### `rate_limited`

请求速度超过了限流允许的范围。响应带 `Retry-After` 响应头，值是 1 到 60 之间的秒数。等这么久之后再重试，并减少同时在途的请求数。

### `internal_error`

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

### `provider_unavailable`

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

## 没有错误码的错误

有三种错误没有 `error.code`，因为网关还没能对这次请求做出判断。这三种按 HTTP 状态码判断。

| HTTP 状态码 | 什么时候出现                                                              | 怎么办      |
| -------- | ------------------------------------------------------------------- | -------- |
| `502`    | 网关没能和 provider 完成这次请求                                               | 稍等后重试    |
| `503`    | 网关没能核对这次请求的 key 和余额。`error.type` 是 `service_unavailable`            | 稍等后重试    |
| `504`    | provider 在时限内什么都没返回，见[超时](https://pirouter.ai/zh/docs/errors.md#超时) | 重试，或改用流式 |

不要假定 `502` 和 `504` 的响应体是 JSON。

## provider 返回的错误

provider 自己返回的错误，pirouter 会带着它原本的状态码和响应体透传给你，不会改写成 pirouter 的错误体，所以响应体遵循你所调用端点的协议。只有 provider 答复的响应带 `X-Pi-Provider` 响应头，pirouter 网关自己产生的错误不带，看这个响应头就能区分两者。

你看到 provider 的 `429` 或 `5xx` 之前，pirouter 已经试过这个模型的其他 provider。见[失败时自动换一家](https://pirouter.ai/zh/docs/routing.md#失败时自动换一家)。

## 超时

pirouter 最多等 provider 95 秒开始返回。这段时间里什么都没收到，请求以 `504` 结束。

这 95 秒的时限卡的是响应的第一个字节，不是整个响应：

- 流式响应开始之后，总时长没有限制。
- 非流式响应是一次性返回的，所以整个回答要在 95 秒内生成完。输出很长、或模型先推理再回答时，请用流式。

客户端的超时要设得比 95 秒长。设短了，会放弃那些网关本来能答复的请求。

## 哪些错误可以重试

| HTTP 状态码                | 能否重试                       |
| ----------------------- | -------------------------- |
| `400`、`401`、`404`、`422` | 不能。同样的请求会得到同样的错误，先改请求或 key |
| `402`                   | 充值之后才行                     |
| `429`                   | 能，等 `Retry-After` 给出的秒数之后  |
| `500`、`502`、`503`、`504` | 能，每次重试之间的等待逐步加长            |

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

## 下一步

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