> ## Documentation Index
> Fetch the complete documentation index at: https://docs.viggle.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 错误与恢复

> 以一致方式处理 V1 错误。

所有 V1 错误均使用统一的 `ErrorBody`：同步 HTTP 错误包裹在 `{"error": ...}` 中，异步资源的 `error` 字段和渲染 SSE 事件使用相同结构。

```json theme={null}
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Insufficient credits to start this job",
    "retryable": false,
    "request_id": "req_123abc",
    "details": {},
    "remediation": {
      "action": "add_credits",
      "retry_after_ms": null
    }
  }
}
```

| 字段            | 类型            | 说明                                                                        |
| ------------- | ------------- | ------------------------------------------------------------------------- |
| `code`        | string        | 下表中的 `SCREAMING_SNAKE_CASE` 错误码，程序逻辑应使用此字段。                               |
| `message`     | string        | 供人阅读的描述，不要解析其文本做逻辑判断。                                                     |
| `retryable`   | boolean       | 重试相同请求是否可能成功。                                                             |
| `request_id`  | string 或 null | 用于关联 Viggle 日志与支持排查。仅当异步工作进程无法恢复原请求 ID 时为 `null`。                         |
| `details`     | object        | 补充结构化信息，可能为空。                                                             |
| `remediation` | object        | `{action, retry_after_ms}`，表示下一步操作。除非建议定时重试，否则 `retry_after_ms` 为 `null`。 |

内部实现错误码不会直接对外暴露。

## 错误码

| `code`                                                                                                                                           | HTTP      | 常见原因                         | 恢复方法                                                                                |
| ------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | ---------------------------- | ----------------------------------------------------------------------------------- |
| `UNAUTHENTICATED`                                                                                                                                | 401       | 未提供凭据。                       | 添加 `Authorization: Bearer YOUR_API_KEY`。                                            |
| `INVALID_CREDENTIAL`                                                                                                                             | 401       | API 密钥或 OAuth 令牌无效、过期。       | 替换凭据。                                                                               |
| `FORBIDDEN`                                                                                                                                      | 403       | 凭据无权访问该资源。                   | 使用正确项目或身份的凭据。                                                                       |
| `INVALID_REQUEST`                                                                                                                                | 400       | 缺少输入、字段格式错误或参数组合不受支持。        | 按对应接口参数表修正请求。                                                                       |
| `INVALID_CHARACTER` / `INVALID_MOTION`                                                                                                           | 400       | 角色或动作来源校验失败。                 | 检查源文件、URL 或素材 ID。                                                                   |
| `UNSUPPORTED_MEDIA`                                                                                                                              | 400 / 422 | 不支持文件类型或编码。                  | 转换为支持的格式。                                                                           |
| `CONTENT_POLICY_VIOLATION`                                                                                                                       | 422       | 素材违反内容政策。                    | 更换素材，不要原样重试。                                                                        |
| `NO_HUMANS_DETECTED`                                                                                                                             | 422       | 未检测到人物。                      | 使用人物清晰可见的图片或视频。                                                                     |
| `VIDEO_TOO_LONG` / `VIDEO_TOO_LARGE` / `VIDEO_RESOLUTION_TOO_HIGH` / `VIDEO_DIMENSIONS_MUST_BE_EVEN` / `VIDEO_UNREADABLE` / `VIDEO_INACCESSIBLE` | 400 / 422 | 源动作视频未满足某项限制。                | 裁剪、重新编码、调整尺寸或重新托管后重试。                                                               |
| `IMAGE_REQUIRED` / `MOTION_VIDEO_REQUIRED`                                                                                                       | 400       | 缺少必要素材。                      | 补充 `image`/`image_url` 或 `motion_video`/`motion_video_url`。                         |
| `INVALID_BACKGROUND_MODE`                                                                                                                        | 400       | 背景或宽高比组合不受支持。                | 使用文档枚举；渲染当前仅支持 `aspect_ratio: source`。                                              |
| `UPLOAD_REQUIRED`                                                                                                                                | 400 / 409 | 所有声明上传尚未完成就提交了 JSON 渲染请求。    | 完成 `renders/prepare` 的每个 `PUT`，并提交匹配的 `upload_completions`。                         |
| `UPLOAD_MISMATCH`                                                                                                                                | 400       | 上传完成项与声明的槽不匹配。               | 对照 prepare 响应检查 `upload_handle`。                                                    |
| `UPLOAD_EXPIRED`                                                                                                                                 | 409       | `PUT` 时上传 URL 已过期。           | 再次调用 `renders/prepare` 获取新计划。                                                       |
| `DRAFT_NOT_FOUND`                                                                                                                                | 404       | 草稿不存在或已过期。                   | 再次调用 `renders/prepare`。                                                             |
| `DRAFT_ALREADY_CONSUMED`                                                                                                                         | 409       | 草稿已用于创建渲染。                   | 使用上次返回的任务，不要重复提交草稿。                                                                 |
| `IDEMPOTENCY_KEY_REUSED`                                                                                                                         | 409       | 相同幂等键配合不同标准化输入。              | 新任务使用新键；获取原任务则重发原输入。                                                                |
| `CHARACTER_NOT_FOUND` / `MOTION_NOT_FOUND` / `RENDER_NOT_FOUND` / `MOTION_TEMPLATE_NOT_FOUND` / `NOT_FOUND`                                      | 404       | 资源不存在或属于其他账户，两者不作区分。         | 核对 ID 及所属身份。                                                                        |
| `MOTION_NOT_READY`                                                                                                                               | 400 / 409 | 可复用动作仍在处理。                   | 轮询至 `ready` 后再渲染。                                                                   |
| `MOTION_MODEL_MISMATCH`                                                                                                                          | 400       | 请求模型或骨架与动作不兼容。               | 根据动作 `type` 核对 `model`/`download_type`。                                             |
| `ID_ALREADY_EXISTS`                                                                                                                              | 409       | `task_id` 已使用。               | 使用新 ID，或将已有任务视为本次结果。                                                                |
| `RENDER_NOT_CANCELLABLE`                                                                                                                         | 409       | 保留错误码，尚无公开的客户端取消操作。          | 常规接入不适用。                                                                            |
| `EXTRACTION_UNAVAILABLE`                                                                                                                         | 502       | 3D 提取后端暂时不可用。                | 退避重试。                                                                               |
| `EXTRACTION_FAILED`                                                                                                                              | 502       | 3D 提取失败。                     | 检查 `vsplat.error`/`glb.error`，仅 `retryable=true` 时重试。                               |
| `INSUFFICIENT_CREDITS`                                                                                                                           | 402       | 余额不足。                        | 在[控制台](https://portal.viggle.ai/dashboard)充值。                                       |
| `RATE_LIMITED`                                                                                                                                   | 429       | 请求过多。                        | 按 `remediation.retry_after_ms` 或 `Retry-After` 退避。                                  |
| `SERVICE_BUSY` / `ALL_WORKERS_BUSY` / `WORKER_STOPPED`                                                                                           | 503       | 临时处理容量不足。                    | 指数退避重试。                                                                             |
| `INTERNAL_ERROR` / `PROCESSING_FAILED` / `TASK_FAILED`                                                                                           | 500       | 意外的服务端错误。                    | 仅 `retryable=true` 时重试；持续失败时附 `request_id` 联系支持。                                    |
| `RESULT_EXPIRED`                                                                                                                                 | 400       | 输出签名 URL 已过期。                | 再次请求导出或下载接口获取新签名。                                                                   |
| `AVATAR_NOT_FOUND` / `ANIMATION_NOT_FOUND`                                                                                                       | 404       | 旧版迁移代理保留错误，新接入使用角色、动作导出即可避免。 | 从 `/v1/avatars`、`/v1/animations` 迁移，见[迁移指南](/zh/v1/production/migrate-from-legacy)。 |

## 重试策略

以错误自身的 `retryable` 和 `remediation` 为准，不要仅按 HTTP 状态写死策略。临时服务错误（`RATE_LIMITED`、`SERVICE_BUSY`、`ALL_WORKERS_BUSY`、`WORKER_STOPPED`，以及 `retryable: true` 的 `INTERNAL_ERROR`）可使用指数退避，并优先遵循 `retry_after_ms` 或 `Retry-After`。400、401、402、403、404、409、422 类错误不要不加修改地重试。

JSON 草稿渲染要求 `Idempotency-Key`，网络超时后使用相同键与请求体会返回原任务，不会重复创建。multipart 渲染与角色、动作创建不使用这一请求头：若已收到响应，使用其中的资源 ID；否则先通过日志与 `X-Request-Id` 确认结果。提供 `task_id` 的创建模式请遵循各自接口说明。

## 失败的异步任务

状态接口返回 HTTP `200` 也可能表示任务失败，资源的 `error` 字段仍使用相同的 `ErrorBody`：

```json theme={null}
{
  "id": "render_123abc",
  "status": "failed",
  "error": {
    "code": "TASK_FAILED",
    "message": "The render could not be completed.",
    "retryable": false,
    "request_id": "req_123abc",
    "details": {},
    "remediation": { "action": "contact_support", "retry_after_ms": null }
  }
}
```

将 `failed` 视为终态，保存资源 ID 和 `request_id` 以便排查。
