# 错误码

> 本网关错误码真值表 — HTTP 状态码 × 三协议错误体对照 + 流式错误行为 + 各端点超时 + 排查步骤

来源：https://zhonkemodel.dflop.top/docs/reference/errors

本网关返回的错误响应**协议自适配** —— 哪个协议端点收到请求,就用哪个协议的官方错误格式回包,SDK 可原生解析。

## 错误体形状 (三协议对照)

**OpenAI 形状** (`/v1/chat/completions`、`/v1/responses`、`/v1/embeddings`,以及 [图像 / 视频端点](./media-apis.md)):

```json
{"error": {"message": "...", "type": "...", "code": "..."}}
```

**Anthropic 形状** (`/v1/messages`):

```json
{"type": "error", "error": {"type": "...", "message": "..."}}
```

**Gemini 形状** (`/v1beta/models/{model}:generateContent`):

```json
{"error": {"code": 402, "message": "...", "status": "RESOURCE_EXHAUSTED"}}
```

> **注意**: 字符串 `code` 字段(如 `quota_exceeded`)**只存在于 OpenAI 形状**。Anthropic 错误体只有 `type` + `message`;Gemini 的 `code` 是数字 HTTP 状态码,枚举语义在 `status` 字段。用 Anthropic / Gemini SDK 时请按下表对应列做匹配。

## 错误码真值表

| HTTP | OpenAI `code` | OpenAI `type` | Anthropic `type` | Gemini `status` | 触发 |
|---|---|---|---|---|---|
| 400 | `model_not_found` | `invalid_request_error` | `not_found_error` | `NOT_FOUND` | model id 不在注册表 |
| 400 | `model_not_allowed` | `invalid_request_error` | `invalid_request_error` | `INVALID_ARGUMENT` | Key 的 `allowed_models` 白名单不含该 model |
| 400 | `invalid_request` | `invalid_request_error` | `invalid_request_error` | `INVALID_ARGUMENT` | 请求体非法 |
| 400 | `tool_not_supported` | `invalid_request_error` | `invalid_request_error` | `INVALID_ARGUMENT` | 工具与上游通道能力不匹配 |
| 400 | `invalid_idempotency_key` | `invalid_request_error` | `invalid_request_error` | `INVALID_ARGUMENT` | `Idempotency-Key` 头格式非法(空 / >200 字符 / 含空白或不可打印字符) |
| 409 | `idempotency_key_reuse` | `invalid_request_error` | `invalid_request_error` | `ALREADY_EXISTS` | 同一把 `Idempotency-Key` 用于了**内容不同**的请求 —— 换一把新键 |
| 409 | `idempotency_in_flight` | `invalid_request_error` | `invalid_request_error` | `ALREADY_EXISTS` | 同一把键的上一次请求仍在处理中 —— 稍等几秒**用同一把键**重试,换键会真的再提交一次 |
| 409 | `idempotency_response_not_cached` | `invalid_request_error` | `invalid_request_error` | `ALREADY_EXISTS` | 原请求已成功并已计费,但响应体过大未留存,无法重放 —— 改用任务列表端点查询 |
| 401 | `invalid_api_key` | `authentication_error` | `authentication_error` | `UNAUTHENTICATED` | Key 缺失 / 无效 / 撤销 / 过期 / 账号停用 |
| 402 | `quota_exceeded` | `insufficient_quota` | `billing_error` | `RESOURCE_EXHAUSTED` | 账户余额耗尽 |
| 403 | `permission_denied` | `permission_error` | `permission_error` | `PERMISSION_DENIED` | 上游 provider 拒绝 (仅透传) |
| 429 | `rate_limit_exceeded` | `rate_limit_error` | `rate_limit_error` | `RESOURCE_EXHAUSTED` | 超出账户的每分钟请求数 / 并发上限,或上游限流 (透传) |
| 500 | `internal_error` | `server_error` | `api_error` | `INTERNAL` | gateway 自身异常 |
| 502 | `upstream_unreachable` | `api_error` | `api_error` | `UNAVAILABLE` | 上游连接失败 |
| 503 | `no_channel_available` | `server_error` | `overloaded_error` | `UNAVAILABLE` | 模型存在但当前协议无可用通道 |
| 504 | `upstream_timeout` | `api_error` | `api_error` | `DEADLINE_EXCEEDED` | 上游超时 (chat 端点 180s) |
| 上游原状态码 | 按状态映射,见 [上游错误透传](#上游错误透传) | 同左 | `api_error` | `UNAVAILABLE` | 上游非 2xx 原状态码透传 |

> Gemini 端点上 402 与 429 共用 `status: "RESOURCE_EXHAUSTED"`,需用数字 `code` (402/429) 区分。

## 400 Bad Request

gateway 自产错误大部分集中在 400 —— 客户最常撞到的就是下面四个。

### `model_not_found`

请求的 model id 不在 pricing 注册表。

**OpenAI 形状**:
```json
{"error": {"message": "model `claude-3.5-opus` is not available", "type": "invalid_request_error", "code": "model_not_found"}}
```

**排查**:
1. 拼写校验 —— `claude-haiku-4-5-20251001` 含日期后缀必须完整
2. [完整模型列表](./models.md) 比对一遍;`GET /api/v1/models/public` 返回的条目里 `callable=false` 的占位 SKU 调用也会返回本错误
3. 注意: model id 存在但**当前协议**没有通道时,返回的是 503 `no_channel_available`,不是本错误,详见 [兼容矩阵](./compatibility-matrix.md)

### `model_not_allowed`

Key 的 `allowed_models` 白名单不含请求的 model。

**排查**: 在 [zhonkemodel.dflop.top/keys](https://zhonkezhonkemodel.dflop.top/keys) 编辑 Key,把目标 model 加进 allow-list,或新建一把不限模型的 Key。注意这是 **400** —— 不要按 403 写分支。

### `invalid_request`

请求体非法 (缺必填字段 / JSON 解析失败 / 字段类型不对)。按 message 提示修正请求体。

### `tool_not_supported`

请求带的工具 (如 `web_search` / `image_generation`) 被路由到不支持该工具的上游通道。

**排查**: 确认所选 model 支持该工具 ([兼容矩阵](./compatibility-matrix.md)),或去掉 `tools` 字段重试。

## 401 Unauthorized

### `invalid_api_key`

401 **只有这一个 code** —— 不带 Key、Key 错、Key 被撤销、Key 过期、账号停用都返回它,靠 message 区分:

| message | 含义 |
|---|---|
| `authentication failed: missing or malformed api key (...)` | 请求没带 Key 或格式不对 |
| `authentication failed: invalid api key` | Key 不存在 (复制不完整 / 已删除) |
| `authentication failed: api key revoked` | Key 被停用 |
| `authentication failed: api key expired` | Key 已过 `expires_at` |
| `authentication failed: account is not active` | 账号被停用 |

**OpenAI 形状**:
```json
{"error": {"message": "authentication failed: invalid api key", "type": "authentication_error", "code": "invalid_api_key"}}
```

**排查**:
1. 检查 Key 是否复制完整 —— 格式是 `sk-gpushare-` + 64 位十六进制,**共 76 字符**
2. 检查 Key 是否在 [zhonkemodel.dflop.top/keys](https://zhonkezhonkemodel.dflop.top/keys) 还存在;Key 可在详情页随时重新查看完整值 (服务端加密存储),不确定就重新复制一遍
3. 检查鉴权方式 —— 四种回退任选: `x-api-key` / `x-goog-api-key` / `?key=` query / `Authorization: Bearer`,详见 [鉴权](./authentication.md)
4. 例外: `GET /v1/models` 只认 `Authorization: Bearer` 和 `x-api-key` 两种 header,**不支持 `?key=`** —— 用 query 鉴权调它会 401

## 402 Payment Required

### `quota_exceeded`

账户余额耗尽。计费走**统一钱包** —— 所有 API Key 共享同一账户余额,Key 本身没有独立预算池,余额耗尽时**所有 Key 同时失效**,「新建 Key」不会带来新额度。

**OpenAI 形状**:
```json
{"error": {"message": "余额不足，请充值后重试。", "type": "insufficient_quota", "code": "quota_exceeded"}}
```

**Anthropic 形状**: `"type": "billing_error"`;**Gemini 形状**: `"status": "RESOURCE_EXHAUSTED"` (数字 `code` 为 402)。

**排查**:
1. 注册自带 **121.32 体验额度**;烧完后去主站 dflop.top/dashboard/billing 充值 (Stripe,最低 404.4,与 zhonkemodel.dflop.top 同账号 SSO 共享余额)
2. 在控制台核对余额与用量,确认是哪类调用消耗大 —— chat/embeddings 按 token,图像按张,视频按秒,详见 [图像 / 视频 / 音乐 API](./media-apis.md)
3. **别等 402 才发现**:用 [`GET /v1/key/balance`](./api-reference.md#get-v1-key-balance) 主动监控 —— 它在余额为 0 时照样 200 返回,不计费也不占速率额度。第三方客户端 / 中转平台的余额显示见 [New API / 中转平台接入](../integrations/new-api.md)

## 403 Forbidden

### `permission_denied`

**仅上游透传** —— gateway 自身不产生任何 403。看到 403 说明上游 provider 拒绝了这次调用 (内容策略 / 区域限制等),message 是上游原话。

**排查**: 切换 model 让请求路由到不同上游;持续出现可通过 support@dflop.top 反馈。

## 429 Too Many Requests

### `rate_limit_exceeded`

两种来源,**用响应头区分**:

| 来源 | 特征 | 处理 |
|---|---|---|
| **平台账户限额** | 带 `Retry-After` + `x-ratelimit-*` 头 | 按 `Retry-After` 等待;并发类的降低同时在飞请求数 |
| **上游通道限流** | 不带 `x-ratelimit-*` 头 | 指数退避重试 (1s → 2s → 4s),或切 model 换上游通道 |

平台限额按**账户**计(名下所有 Key 共享额度),两个维度:每分钟请求数(60 秒滑动窗口)与最大并发(同时在飞的请求数)。**全部 `/v1/*` 请求都计入**,包括异步任务的状态轮询。message 会写明命中的是哪个维度,例如:

```json
{"error":{"message":"requests per minute limit reached (120/min); retry after 3s","type":"rate_limit_error","code":"rate_limit_exceeded"}}
```

限额存在时成功响应也带 `x-ratelimit-*` 头,可据此自适应节流;当前账户的上限见 [控制台 API Keys 页](https://zhonkezhonkemodel.dflop.top/dashboard/keys)。详见 [API 参考 · 速率限制](./api-reference.md#速率限制)。

## 500 Internal Server Error

### `internal_error`

gateway 自身异常。罕见。

**排查**: 重试 1-2 次;如持续,通过 support@dflop.top 反馈,附上**时间戳 + model id + 完整错误响应体** (如有,加上 Cloudflare `cf-ray` 响应 header)。错误响应里没有 `request_id` 字段,不用找。

## 502 Bad Gateway

### `upstream_unreachable`

上游**连接失败** (DNS / TCP / TLS 层面够不着上游)。只有这种场景固定返回 502 —— 上游自身返回的 5xx 走 [原状态码透传](#上游错误透传),不会被改写成 502。

**排查**: 重试 (上游偶尔抖动),或切换 model。

## 503 Service Unavailable

### `no_channel_available`

请求的 model 在**当前协议端点**下没有可用上游通道 —— 包括所有通道 disabled / unhealthy,也包括该 model 本身不支持这个协议 (比如用 `/v1/messages` 调一个只有 OpenAI 协议通道的 model)。

**排查**:
1. 先查 [兼容矩阵](./compatibility-matrix.md) 确认 model × 协议组合受支持
2. 切换 model
3. 持续不可用通过 support@dflop.top 反馈。gateway 健康探测**每 6 小时**一轮 (部署后有一次启动 warmup),所以「等几分钟重试」对 unhealthy 通道基本无效,直接切 model 更快

## 504 Gateway Timeout

### `upstream_timeout`

上游响应超时。各端点上游超时上限不同:

| 端点 | 上游超时 |
|---|---|
| chat 四协议端点 (`/v1/chat/completions` 等) | **180s** (总时长,流式同样适用) |
| `POST /v1/images/generations` / `POST /v1/images/edits` | 单跳 240s / 渠道阶梯合计 280s(客户端建议 ≥300s;`gpt-image-2` 实测 30–215s)。⚠️ 超 90s 的同步轮会以 `200` + chunked 保活穿过 CDN,**因此超 90s 之后才失败的轮返回 `200` + `{"error":...}` 而非真实状态码** —— 需要干净失败语义请用 `"async": true` |
| `POST /v1/videos/generations` (提交) | 60s (任务异步执行,生成不占请求时长) |
| `POST /v1/embeddings` | 30s |

**排查**:
1. 降 `max_tokens` 或拆分任务为多次调用
2. 用 `stream: true` 可以更早拿到首 token,但**整条流仍受 180s 总时长上限约束** —— 流式不是不限时
3. 客户端 SDK 的 timeout 建议设 **≥ 200s**,留出余量
4. 超长任务 (视频生成 / 异步出图) 走异步提交 + 轮询,不受单请求超时影响,详见 [图像 / 视频 / 音乐 API](./media-apis.md);被你自己的客户端超时掐断的调用,在 [logs.dflop.top](https://logs.dflop.top) 里仍会以终态入账(`interrupted` 或 `success`),用响应头 `x-gateway-trace` 反查即可

## 上游错误透传

上游返回非 2xx 时,gateway **原状态码透传** (上游 500 → 响应 500,上游 429 → 响应 429),message 解包成上游原话,OpenAI 形状的 `type` / `code` 按状态码映射:

| 上游状态 | OpenAI `code` | OpenAI `type` |
|---|---|---|
| 400 / 422 | `invalid_request` | `invalid_request_error` |
| 401 | `invalid_api_key` | `authentication_error` |
| 403 | `permission_denied` | `permission_error` |
| 404 | `not_found` | `invalid_request_error` |
| 429 | `rate_limit_exceeded` | `rate_limit_error` |
| 5xx / 其他 | `upstream_error` | `api_error` |

**排查**: 重试 1-2 次 (上游偶尔抖动),或切换 model 路由到不同上游通道。

## 流式中的错误

流式请求一旦以 **HTTP 200 开流**,中途出错就**无法再改状态码** —— 错误只能体现在流本身:

- **流提前终止**: 上游中途失败时,gateway 不注入自己的错误帧,流直接结束 —— OpenAI SSE 不会收到 `data: [DONE]` 终止帧,最后一个 chunk 没有 `finish_reason` (Anthropic 流则缺 `message_stop` 事件)
- **上游错误帧透传**: 如果上游在断流前发出协议内的错误事件 (如 Anthropic 的 `event: error` 帧),gateway 原样转发
- **例外 —— 内置工具路径**: `/v1/chat/completions` 带 `web_search` / `image_generation` 内置工具的请求走专用通道,中途失败时 gateway **会合成**一个错误 chunk (`{"error":{"message":…,"type":"api_error","code":"upstream_error"}}`) 再跟 `data: [DONE]` 收尾,详见 [流式响应指南](../guides/streaming.md)

**客户端应对**:
1. 不要只依赖连接关闭 —— 校验是否收到 `data: [DONE]` / `finish_reason` / `message_stop`,缺失即视为不完整流
2. 不完整流按失败处理,带退避重试

**计费口径**: 中断前已传输的部分按实际 usage 结算 (上游没来得及发 usage chunk 时,按已输出字符估算 output tokens),中断的 turn 不会重复扣费也不会免费。

## 排查决策树

```
请求失败
├─ 400 → model 拼写 / Key allow-list / 请求体 / 工具不被通道支持
├─ 401 → Key 问题 → 控制台重新查看并复制 Key (76 字符), 核对鉴权 header
├─ 402 → 账户余额耗尽 → dflop.top/dashboard/billing 充值 (新建 Key 没用)
├─ 403 → 上游拒绝 (透传) → 切 model
├─ 429 → 带 x-ratelimit-* 头 = 平台限额 (按 Retry-After 等待 / 降并发)
│         不带 = 上游限速 → 退避重试
├─ 503 → 当前协议无可用通道 → 查兼容矩阵 / 切 model
├─ 其余 5xx → 上游 / 网关问题 → 重试 1-2 次, 切 model
├─ 流式中断 (200 后) → 校验 [DONE] / finish_reason → 按失败重试
└─ 网络层 (无 HTTP 响应) → 检查防火墙 / DNS / TLS 是否到达 zhonkeapi.dflop.top
```

## 调试技巧

打开 SDK 的 debug 模式看完整请求 / 响应:

```python
# OpenAI Python SDK
import logging
logging.basicConfig(level=logging.DEBUG)

# Anthropic Python SDK
import os
os.environ["ANTHROPIC_LOG"] = "debug"

# curl 全量
curl -v -i https://zhonkezhonkeapi.dflop.top/v1/chat/completions ...
```

响应 header 的 `X-Protocol-Translation` 标注了这次请求走的跨协议翻译路径,排查协议相关问题时值得带上。错误响应体和 header 里**没有** `request_id`;反馈问题时请附时间戳 + model id + 完整错误体 (+ Cloudflare `cf-ray` header)。
