# 错误处理

> 查看错误响应结构和全部错误码，区分请求被拒绝与转录失败，并判断哪些情况可以重试。

Canonical: https://transcript1.com/zh/docs/errors
Language: zh-Hans
Last updated: 2026-10-19

先区分请求错误和转录失败：请求错误发生在调用API时，表示请求未被接受；转录失败则表示请求已被接受，但后续处理出错，任务的`status`变为`failed`。

## 读取错误响应

`/v1`接口拒绝请求时，统一返回以下结构：

```json
{
  "error": {
    "code": "insufficient_minutes",
    "message": "Not enough minutes",
    "retryable": false,
    "action_url": "https://transcript1.com/dashboard/billing",
    "minutes_needed": 20,
    "minutes_remaining": 3
  }
}
```

用`code`判断如何处理错误。`message`可以展示给用户，但文案可能调整，不要依赖它做逻辑判断。`retryable`为`true`表示原请求稍后重试有可能成功。

部分错误还会在同一错误对象中提供补充字段：

| 字段 | 对应错误码 | 说明 |
|---|---|---|
| `action_url` | `insufficient_minutes` | 前往购买套餐或充值的链接。 |
| `minutes_needed`、`minutes_remaining` | `insufficient_minutes` | 分别是本次请求所需分钟数和当前可用分钟数。所需时长尚不确定时，`minutes_needed`为`null`。 |
| `supported_platforms` | `unsupported_platform` | 可用的`platform`值：`["youtube", "x", "tiktok", "instagram", "facebook", "bluesky", "twitch", "dailymotion", "pinterest", "linkedin", "snapchat"]`。 |
| `missing_chunks` | `upload_incomplete` | 服务器尚未收到的分块索引，需要补传。 |
| `max_bytes` | `media_too_large` | 当前允许上传的最大文件字节数。 |
| `params` | `invalid_request` | 请求体或查询参数校验失败时，按字段列出具体问题的对象。 |

## 请求被拒绝时的错误码

| HTTP状态码 | `code` | 能否直接重试 | 原因和处理方式 |
|---|---|---|---|
| 400、422 | `invalid_request` | 否 | 请求参数或请求体字段缺失、值无效，或请求体不是合法JSON。例如，`diarize`不能与`source: "captions"`一起使用，`reuse_recent`不能与`webhook_url`一起使用。 |
| 422 | `invalid_url` | 否 | 链接无效，或填写的`platform`与链接不一致。请使用YouTube、X、TikTok、Instagram、Facebook、Bluesky或[来源与转录设置](https://transcript1.com/zh/docs/sources-and-options)中其他支持的平台链接。 |
| 422 | `unsupported_platform` | 否 | `platform`填入了不支持的平台。 |
| 422 | `unsupported_media` | 否 | 文件后缀不在支持列表中。 |
| 401 | `unauthorized` | 否 | 未提供认证凭据，或凭据无效、过期、已撤销；上传Token无效或过期也会返回此错误。 |
| 403 | `insufficient_scope` | 否 | OAuth Token没有所需的`transcriptions:read`或`transcriptions:write`权限。 |
| 403 | `email_not_verified` | 否 | 邮箱尚未验证，验证后才能创建转录任务。 |
| 402 | `insufficient_minutes` | 否 | 可用分钟数为0，或不足以完成本次转录。 |
| 402 | `no_active_plan` | 否 | 没有生效中的付费套餐，却尝试充值。只有控制台的计费接口会返回此错误，转录接口不会。 |
| 404 | `not_found` | 否 | 找不到该转录任务，或任务属于另一个团队。 |
| 409 | `upload_incomplete` | 否 | 分块尚未传齐。补传缺失分块，再调用完成上传接口。 |
| 409 | `invalid_state` | 否 | 任务已不在等待上传的状态，不能继续传分块或确认上传完成。 |
| 409 | `idempotency_conflict` | 否 | 同一个`Idempotency-Key`已用于参数不同的请求。 |
| 413 | `media_too_large` | 否 | 文件大小超出当前上限，详见[文件上传](https://transcript1.com/zh/docs/uploads)。 |
| 413 | `invalid_request` | 否 | JSON请求体超过1MB。超限的是上传文件时，错误码为`media_too_large`。 |
| 429 | `rate_limited` | 是 | 每分钟请求数超限。按`Retry-After`指定的秒数等待后重试。 |
| 429 | `too_many_active_jobs` | 是 | 同时处理的转录任务或尚未完成的上传数量超限。按`Retry-After`指定的秒数等待后重试。 |
| 500 | `internal_error` | 是 | 服务内部出错，稍后重试。 |
| 503 | `service_unavailable` | 是 | transcript1暂时无法提供服务，稍后重试。 |

浏览器用登录Cookie认证、而非Bearer凭据时，API还会校验请求来源。来自其他站点的请求返回`403 forbidden_origin`。通过`Authorization`请求头认证的API调用不受这项检查影响。

所有`429`响应都会带上`Retry-After`，告诉客户端需要等待多少秒。各项配额见[计费与限制](https://transcript1.com/zh/docs/billing-and-limits)。

## 什么时候重试

- 只有`retryable`为`true`才直接重试，对应`rate_limited`、`too_many_active_jobs`、`internal_error`和`service_unavailable`。有`Retry-After`时按它等待；没有时，逐步延长重试间隔。
- 重试`POST /v1/transcriptions`务必沿用原来的`Idempotency-Key`，避免首次请求其实已成功，却因再次创建任务而重复扣费。
- 遇到其他错误码，先解决问题，再发送请求。

## 转录过程中失败

请求成功返回，不代表转录一定成功。任务后续失败时，`status`会变为`failed`，转录对象中会带有`error: { "code", "message" }`。轮询状态或收到`transcription.failed`[Webhook](https://transcript1.com/zh/docs/webhooks)后，读取`error`判断原因。

| `error.code` | 失败原因 | 是否需要重新提交 |
|---|---|---|
| `media_unavailable` | 视频不存在或已无法访问。 | 不要直接重试，先检查URL。 |
| `media_private` | 视频已设为私有。 | 不要直接重试，改用公开帖子，或公开、非公开（unlisted）的YouTube视频。 |
| `login_required` | 必须登录平台账号才能访问。 | 这是永久性失败，不会重试。 |
| `no_audio` | 视频不含音轨。 | 这是永久性失败，不会重试。 |
| `age_restricted` | 视频受年龄限制。 | 重试原链接无效，改为上传文件。 |
| `live_stream` | 直播仍在进行，或尚未开始。 | 等直播结束后再提交。 |
| `no_captions` | 选择了`captions`，但没有可用字幕。 | 改用`source: "auto"`或`"stt"`。 |
| `media_too_long` | 音频或视频超过语音转文字的5小时上限。 | 先拆分录音或视频，再分别提交。 |
| `unsupported_media` | 文件无法读取，或不含音轨。 | 改传受支持的文件。 |
| `no_speech` | 未检测到语音。 | 不要重试。 |
| `unsupported_language` | 不支持录音中的语言。 | 先将`language`改为支持的语言代码或`"auto"`。 |
| `insufficient_minutes` | 转录扣费前，可用分钟数已用完。 | 充值后再提交。 |
| `fetch_failed` | 多次获取音频或视频均失败。 | 可以稍后重新提交。 |
| `transcription_failed` | 语音转文字已尝试多次，仍未成功。 | 可以稍后重新提交。 |

如果转录失败或被取消，就不会扣费；此前为该任务扣除的分钟数会退还。
