# 错误与重试
> 统一错误信封、retryable 重试规则与完整错误码表。

> 下表由 Beatra 的公开错误码定义自动生成。

Beatra 的每个公开错误响应都使用统一的错误信封。`error.code` 取自下表中稳定的公开值；`error.retryable` 告诉客户端，原样重试是否有可能成功。

每个错误响应体的结构如下：

```json
{
  "error": {
    "code": "<machine code>",
    "type": "<error family>",
    "message": "<human description>",
    "retryable": true,
    "param": "/field",
    "details": {},
    "request_id": "req_..."
  }
}
```

## 怎么分支

| 看到 | 该做 |
|---|---|
| `retryable: true` | 短暂退避后，可以用**完全相同的请求**和同一个 `Idempotency-Key` 重试。响应带有 `Retry-After` 头时请遵守；`429` 响应还会附带 `X-RateLimit-*` 头。 |
| `retryable: false` | 原样重试会得到同样的结果。客户端需要修改请求、修正凭据，或把错误展示给用户。在不可重试的错误上循环重试是 bug。 |
| `error.param` | 如有，是指向请求体中出错字段的 JSON Pointer（RFC 6901）。 |
| `error.type` / `error.details` / `error.request_id` | 分别给出稳定的错误类别、修正所需的信息和追踪标识。 |
| `error.message` | 诊断用的文字，不能作为分支依据。任务在模型服务返回后最终失败时，它会保留模型服务的原始措辞，并已做过凭据、签名 URL、控制字符和长度方面的安全处理。 |

如果有 `error.details.recovery`，它会在不改变顶层错误信封的前提下，给出可用于分支的处理动作。`requires_input_change` 表示提交的内容是否必须修改。`client_request_id: new` 表示修正后的工作或已终止的工作是一个新的逻辑请求；否则按 `retryable` 和该端点的幂等规则处理。

```json
{
  "details": {
    "recovery": {
      "action": "fix_arguments_and_resubmit",
      "requires_input_change": true,
      "client_request_id": "new"
    }
  }
}
```

## 认证与账号

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `unauthorized` | 401 | 否 | 缺少认证凭据，或格式不正确。请发送 `Authorization: Bearer <API key>`。 |
| `invalid_api_key` | 401 | 否 | API Key 无效、已停用、已吊销或不存在。请在控制台「开发 → API Key」创建或轮换 Key，再用新 Key 重试。 |
| `api_key_region_mismatch` | 400 | 否 | API Key 的区域前缀与当前端点不一致。请调用与该 Key 区域对应的 API 主机，或改用为本区域签发的 Key。 |

**展开其余 3 个**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `tenant_disabled` | 403 | 否 | 账号已被暂停或停用。请联系支持；重试无法成功。 |
| `forbidden` | 403 | 否 | 调用方没有执行此操作的权限。请使用具备相应权限的凭据；原样重试无法成功。 |
| `email_send_failed` | 502 | 是 | 登录验证码邮件暂时没能发出。请稍等片刻后重新获取验证码。 |

## 计费

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `insufficient_balance` | 402 | 否 | 积分不足：本次请求没有开始，也没有扣费。请到 https://console.beatra.ai/wallet?intent=buy 充值，积分立即生效；然后重试同一个请求。无需重新安装或重新授权。 |
| `billing_failed` | 500 | 是 | 扣费或退款在多次重试后仍失败。请用相同的 Idempotency-Key / client_request_id 重试；同一个请求标识保证不会重复扣费。 |
| `payment_provider_unavailable` | 503 | 否 | 此支付方式暂未配置收款服务。请在控制台选择其他支付方式。 |

## 容量与可用性

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `rate_limited` | 429 | 是 | 超出了调用方的速率限制。请在 `Retry-After` 指定的时间后重试；`X-RateLimit-*` 响应头会给出当前额度。 |
| `model_unavailable` | 503 | 是 | 所请求的模型暂时不可用。请退避后重试，或换一个可选模型（`beatra.models.list` 或 `GET /v1/catalog/models`），或使用 `model=auto`。 |
| `model_request_failed` | 502 | 是 | 模型请求在可重试的服务错误之后仍然失败。请退避后重试；如果持续出现，请调整输入或换一个模型。 |

**展开其余 4 个**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `model_timeout` | 504 | 是 | 模型请求超时。请退避后重试。 |
| `model_rate_limited` | 429 | 是 | 模型容量被限流。请退避后重试。 |
| `model_output_invalid` | 502 | 是 | 模型已成功生成，但多次尝试后仍无法下载生成的结果文件。任务记为失败，没有可用的结果文件。 |
| `internal_error` | 500 | 是 | 未分类的服务端错误。请用相同的幂等标识重试；如果持续出现，请附上 request_id 反馈问题。 |

## 其他错误码

**请求校验 15 个 ⌄**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `invalid_request` | 422 | 否 | 请求体未通过结构校验。`param` 指向第一个出错的字段；`details.errors` 列出每一处错误及其 `loc` 和原因。修正这些字段后重新发送。 |
| `skill_package_format_invalid` | 422 | 否 | Skill 包标识格式不正确。请使用不超过 64 个字符、由小写字母和连字符组成的 slug，以及合法的 SemVer 包版本号。 |
| `unsupported_capability` | 400 | 否 | 该能力不存在或已停用。`GET /v1/catalog/capabilities` 会列出当前可用的能力。 |
| `unsupported_model` | 400 | 否 | 该模型不存在，或不能用于此能力。请用 `beatra.models.list` 或 `GET /v1/catalog/models` 查询可选模型，或使用 `model=auto`。 |
| `unsupported_option` | 422 | 否 | 所选的具体模型不支持请求中的某个取值或控制项。`param` 指出字段，`details.candidate_failures[]` 给出具体失败码（如 `unsupported_resolution`、`unsupported_duration`、`unsupported_aspect_ratio`），以及收到的值和支持的值。请修改该字段或换一个模型；使用 `model=auto` 时，只有所有候选模型都无法满足请求才会返回此错误。 |
| `no_eligible_model` | 422 | 否 | 没有任何在线模型能完整满足这次 `model=auto` 请求。`details.candidate_failures[]` 列出每个候选模型的拒绝原因；只修改不兼容的字段，或选用列出的某个具体模型。 |
| `voice_model_incompatible` | 422 | 否 | 所请求的音色在所请求的模型上不可用。请使用 `model=auto`、兼容的模型，或从音色列表中另选一个音色。 |
| `unsupported_input_modality` | 422 | 否 | 所选模型不支持请求中的某种输入类型（如图片、音频或文件）。`param` 指向第一个出错的字段；请去掉它，或选用支持该输入的模型。 |
| `context_length_exceeded` | 422 | 否 | 请求超出了所选模型的上下文长度。请缩短输入，或选用上下文更长的模型。 |
| `safety_rejected` | 400 | 否 | 请求未通过内容安全审核。请让用户检查提示词和每一个输入素材，修改或替换可能不安全的内容后，用新的 client_request_id 提交新任务。原样重试不会有帮助。 |
| `content_filtered` | 502 | 否 | 生成过程中，安全过滤拦截了输出。请改写提示词或换一个模型；原样重试通常仍会被拦截。 |
| `not_found` | 404 | 否 | 请求的 HTTP 资源或端点不存在。请检查路径和标识；原样重试无法成功。 |
| `streaming_not_yet_implemented` | 501 | 否 | 旧版本兼容用的错误码：早期部署能识别 `stream=true`，但没有启用流式输出。 |
| `invalid_window` | 422 | 否 | 时间范围无效。 |
| `invalid_cursor` | 400 | 否 | 分页游标格式不正确。 |

**回调 3 个 ⌄**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `callback_url_required` | 422 | 否 | 选择了回调签名密钥时，必须提供回调地址。请添加 `callback_url`，或去掉 `callback_signing_key_id`。 |
| `callback_signing_key_not_found` | 404 | 否 | 回调签名密钥不存在，或当前账号无权查看。请在控制台查看签名密钥列表，并传入一个有效的密钥 ID。 |
| `callback_signing_key_inactive` | 422 | 否 | 该回调签名密钥已停用，不能用于新任务。请选择一个启用中的密钥；不需要签名时，可以不传密钥 ID。 |

**媒体输入 5 个 ⌄**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `invalid_media` | 422 | 否 | 媒体输入格式错误或无法解码。请重新导出或重新编码文件后再提交；`param` 指出出错的字段。 |
| `unsupported_media_type` | 422 | 否 | 此能力不支持该媒体类型。请转换为支持的格式（见能力页或模型约束）后重新发送。 |
| `media_too_large` | 413 | 否 | 媒体输入超过了大小上限。请压缩或裁剪输入，或先上传，再传入素材引用（artifact）。 |
| `media_fetch_failed` | 422 | 是 | Beatra 无法访问某个输入资源。请确认该资源可以通过 HTTPS 访问，或先上传，再传入素材引用（artifact）。 |
| `upload_stalled` | 408 | 是 | 上传太久没有发送数据，或超过了上传时长上限。请向同一个上传地址重新发送同一个 PUT；如果上传授权已过期，请用 `beatra.assets.upload` 重新申请一个。 |

**任务与资源 11 个 ⌄**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `task_not_found` | 404 | 否 | task_id 不存在，或不属于当前账号。请使用创建任务时返回的 task_id；可以用 `GET /v1/tasks` 或 `beatra.tasks.list` 列出最近的任务。 |
| `conflict` | 409 | 否 | 操作与资源的当前状态冲突；对于取消任务，这表示任务会继续执行。请按 `details.action` 处理（通常是继续轮询同一个任务），不要重新提交。 |
| `result_undeliverable` | 502 | 否 | 已完成的结果无法返回：体积过大、嵌套过深，或不是合法的 JSON。不要重复提交同样的查询。 |
| `artifact_not_found` | 404 | 否 | artifact_id 不存在，或不属于当前账号。请重新上传媒体，并使用新返回的 artifact ID。 |
| `voice_not_found` | 404 | 否 | voice_id 不存在，或不属于当前账号。可以用 `GET /v1/voices` 或 `beatra.voices.list` 列出可用音色。 |
| `voice_activation_required` | 422 | 否 | 这个音色还是免费试听，激活后才能用于语音合成。请先向用户确认激活价格，再调用 `beatra.voices.activate`。 |
| `price_confirmation_required` | 422 | 否 | 激活报价已过期或已变化。请把新报价告知用户并取得同意，然后用新的 `confirmation_token` 和 `confirm_credits` 再次调用 `beatra.voices.activate`。 |
| `voice_preview_expired` | 422 | 否 | 这个试听音色已过期，不能再激活或用于合成。请重新克隆。 |
| `voice_sample_rejected` | 422 | 否 | 声音样本被拒绝。请查看 `details.reason`，修正样本后用新的 `client_request_id` 重新克隆。 |
| `voice_limit_reached` | 409 | 否 | 这个账号等待激活的克隆音色已达上限。请激活一个，或在桌面端删除一个，也可以用 `DELETE /v1/voices/{voice_id}` 删除；等待中的音色 7 天后也会过期。 |
| `voice_activation_daily_limit` | 429 | 否 | 这个账号今天已激活 3 个克隆音色，达到每日上限，本次未扣费。如需今天继续激活，请联系 Beatra 客服；上限在 UTC 00:00（北京时间 08:00）重置。 |

**幂等与响应模式 2 个 ⌄**

| 错误码 | HTTP | 可重试 | 何时出现，怎么处理 |
|---|---|---|---|
| `idempotency_conflict` | 409 | 否 | 同一个 `Idempotency-Key` / `client_request_id` 用在了不同的请求体上。修改过的请求请换一个新标识；要原样重试同一个请求，就复用原标识。决定之前，先查看已有的任务。 |
| `request_in_progress` | 409 | 是 | 同一个幂等标识对应的请求还在处理中。请稍后用同一个标识重试，会拿到原请求的响应。 |

## 异步任务失败

一次生成可能被成功受理，之后以 `status: failed` 结束。REST 任务查询、MCP `beatra.tasks.get` 和回调返回同一个 `Task.error` 对象，包含 `code`、`type`、`message`、`retryable`，以及可选的 `param`、`details` 和 `request_id`。读到失败的任务，说明任务已到最终状态，不是 MCP 协议错误。

`model_output_invalid` 表示模型已成功生成，但 Beatra 多次尝试后仍无法下载生成的结果文件。这个失败的任务没有可用的结果文件。

## MCP 工具错误

MCP 工具调用失败时，返回 `isError: true` 的工具结果，`structuredContent.error` 使用与 REST 错误信封**相同的字段**：`code`、`type`、`message`、`retryable`、可选的 `param`（指向工具参数的 JSON Pointer）、可选的 `details`，另加 JSON-RPC 的 `jsonrpc_code`。请和 REST 一样按 `code` 与 `retryable` 分支处理。

只有一个 MCP 专有错误码：`insufficient_scope`，表示 OAuth 授权缺少所需的 scope，`missing_scopes` 会列出缺少的项。请重新运行 Beatra 设备授权；不重新授权就重试不可能成功。意外的服务端故障会以 `internal_error` 工具结果返回，不会是裸 HTTP 错误。

---

本页由 52 个公开错误码生成。另有 25 个内部、管理端或服务商接入专用的错误码，不在公开文档中列出。
