错误处理
错误响应格式、按 HTTP 状态码整理的错误码、每种错误的原因与处理方式,以及重试决策表。
本页内容
本页列出 api.tokentosea.com 返回的错误,以及每种错误应该怎样处理。核心原则:结果明确的错误修正后用新幂等键重发;结果未知的情况用原幂等键查询,不要重新提交。
前提:已创建密钥并把它设置为环境变量 TOKENTOSEA_API_KEY。
错误格式#
JSON
{
"error": {
"code": "endpoint_not_verified",
"message": "可选:经过脱敏的厂商说明,最多 300 个字符"
}
}code是稳定的机器可读标识,请按它编写处理逻辑,不要解析message。message只在厂商返回了可公开的说明时出现;其中的网址和凭据会被替换为[URL]、[redacted]。- 只有入口(
api.tokentosea.com)自身拒绝的错误带x-should-retry: false;由区域执行节点返回、经入口转发的错误(余额、并发、限额、厂商错误等)不带这个头,OpenAI 与 Anthropic SDK 默认会对其中的409、429和5xx自动重发。请关闭 SDK 自动重试(max_retries=0/maxRetries: 0)。平台不发送Retry-After和限流响应头。 - 请求通过参数校验后,响应头
X-Request-Id回显幂等键;更早阶段的错误(如鉴权失败)没有这个头。
重试决策#
| 收到 | 含义 | 做法 |
|---|---|---|
400 413 415 422 | 请求本身不被接受,未执行、未计费 | 修正请求,用新键发起 |
422 且响应体是结果信封(含 run_id) | 同一个键的原调用已失败 | 按 billing_status 判断是否扣费,见失败的结果信封 |
401 403 | 鉴权或权限问题,未执行 | 检查密钥、范围与限额 |
404(POST) | 接口或型号不存在 | 检查路径与型号 ID |
409 main_wallet_authorization_failed | 余额、并发或幂等键冲突,未执行 | 见下文 |
409 request_already_accepted / request_already_dispatched | 同一个键的原调用已受理 | 用原键查询结果 |
429 resource_daily_limit | 文件或音色的每日额度已用完 | 次日再试 |
202 | 已受理,未完成 | 用原键查询,直到终态 |
502 503 等所有 5xx | 结果未知:可能发生在厂商返回结果之后 | 用原键查询,不要换键重发;查询返回 404 时用原键原样重发 |
| 网络错误 / 超时 | 结果未知 | 用原键查询 |
main_wallet_authorization_failed#
鉴权、范围、限额、余额、并发和幂等检查由主站统一执行,这些检查的失败目前都以 main_wallet_authorization_failed 返回,只能通过 HTTP 状态码区分大类。按状态码逐项排查:
| HTTP | 可能原因 | 排查方法 |
|---|---|---|
| 400 | max_tokens 等输出上限超过型号允许值;输入超过型号上限(纯文本请求的 JSON 字节数 + 4096 超过型号的最大输入 token 数,多数对话型号为 1,048,576,见限制与配额);请求条件没有对应的价格档位 | 降低输出上限、缩短输入,或调整分辨率、时长等参数 |
| 401 | 密钥在请求过程中被撤销、删除或到期 | 在「我的 Key」检查密钥状态 |
| 403 | 型号不在密钥的调用范围内(服务商或型号);本次预留会超出密钥的 token 或金额上限;使用了不能调用模型的密钥;型号暂未定价 | 用 GET /v1/models 确认该密钥可调用此型号;在「我的 Key」检查限额与周期 |
| 409 | 可用余额(余额减未结算预留)不足以覆盖本次预留;账号同时进行中的调用已达 8 个;同一个幂等键已用于不同的请求体 | 充值;等待进行中的调用结束;换用新的幂等键 |
| 503 | 主站暂时不可用。可能发生在受理前,也可能发生在厂商已返回结果、等待结算时 | 用原键查询结果,不要换键重发 |
401 / 403 时也可能看到 main_key_authorization_failed,含义相同:密钥无效(401,工具密钥也属于这种情况)或这类密钥不能调用模型(403,如订单专用密钥)。
按状态码的错误码#
400 Bad Request#
error.code | 原因 |
|---|---|
invalid_json_body | 请求体不是合法 JSON,或 Content-Type 与内容不符 |
query_parameters_not_supported | 推理接口不接受 URL 查询参数 |
idempotency_key_invalid | 幂等键不是 16–128 个字母、数字或 _.:- |
request_too_deep | JSON 嵌套超过 64 层 |
system_one_invalid_json / system_one_invalid_multipart | System One 请求体无法解析 |
401 Unauthorized#
error.code | 原因 |
|---|---|
invalid_api_key | 缺少密钥,或不是 16–2048 个可打印 ASCII 字符 |
main_key_authorization_failed | 密钥不存在(包括误用工具密钥 tts_tool_…)、已撤销、已删除、已过期,或账号不可用 |
403 Forbidden#
error.code | 原因 |
|---|---|
main_key_authorization_failed | 密钥类型不能调用模型(如订单专用密钥) |
main_wallet_authorization_failed | 见上文 |
model_not_allowed | 资源接口(文件、音色)调用了密钥范围外的型号 |
router_identity_required | 直接访问了内部执行节点。请只使用 api.tokentosea.com |
404 Not Found#
error.code | 原因 |
|---|---|
endpoint_not_offered / model_not_offered | 路径不存在,或型号 ID 不在目录中(检查大小写) |
result_not_found | 该密钥下没有这个幂等键的结果 |
task_not_found | 任务编号不存在或不属于该密钥 |
asset_not_found | 资产不存在、不属于该密钥或已超过保留期 |
resource_not_found | 文件或音色不存在、不属于该密钥或已过期 |
409 Conflict#
error.code | 原因 |
|---|---|
main_wallet_authorization_failed | 余额不足、并发已满或幂等键冲突,见上文 |
request_already_accepted / request_already_dispatched | 同一个幂等键的原调用已受理,查询结果即可 |
idempotency_conflict | 文件、音色或异步向量请求:同一个幂等键对应了不同内容 |
file_upload_already_accepted / voice_creation_already_accepted | 同一个幂等键的上传或音色创建正在处理 |
413 Payload Too Large#
error.code | 原因 |
|---|---|
invalid_json_body | JSON 请求体超过 48 MB |
multipart_limit_or_invalid_field | multipart 超限:文件超过 25 MB、多于 1 个文件、多于 40 个字段或单字段超过 1 MB |
request_too_complex | 请求结构过于复杂(节点过多) |
system_one_request_size / cloudflare_request_size | System One 请求超过型号上限 |
415 Unsupported Media Type#
error.code | 原因 |
|---|---|
system_one_content_type | System One 只接受 application/json 或 multipart/form-data |
system_one_encoding_not_supported | Content-Encoding 只能是 gzip 或 zstd(或不压缩) |
422 Unprocessable Entity#
请求格式正确,但该型号不支持这样调用。最常见的是能力类错误:
error.code | 原因 | 处理 |
|---|---|---|
model_operation_not_supported | 型号不提供这个接口 | 查看型号的 verified_endpoints |
endpoint_not_verified | 接口存在但该型号未验收 | 同上 |
response_mode_not_verified | 该接口不支持当前响应方式(JSON 或流式) | 查看 response_modes |
streaming_required | 该型号只支持流式 | 加 "stream": true |
input_modality_not_verified | 请求包含未开放的输入类型(图像、音频、视频、文档) | 查看 verified_inputs |
stateful_responses_not_supported | Responses 中用了 store: true、previous_response_id、conversation 或 background | 改为无状态调用 |
hosted_tools_not_priced | 使用了厂商托管工具或联网搜索 | 只使用 function / custom 工具 |
auxiliary_product_not_priced | 使用了未单独定价的附加产品(如显式缓存会话、MCP 服务器、版权素材) | 移除相关字段 |
explicit_cache_not_priced / cache_ttl_not_priced / cache_breakpoint_limit / cache_options_not_priced | 显式缓存在该型号未定价,或 TTL、断点数超出允许范围 | 改用隐式缓存,或按型号说明调整 |
audio_output_not_priced | 请求音频输出,但该型号的音频输出未定价 | 只请求文本输出 |
multiple_outputs_not_supported | 请求了多个候选输出(n 大于 1) | 设为 1 |
媒体与资源类错误:
error.code | 原因 |
|---|---|
input_media_unavailable | 平台下载你提供的媒体地址时收到非 2xx 响应或跳转,见媒体输入 |
too_many_input_media | 单次请求超过 20 张图片、8 段视频或共 30 个媒体 |
media_duration_invalid / media_data_invalid | 音视频时长无法识别或超过 1 小时;data URI 格式不正确 |
video_input_invalid / unsupported_video_role | 视频 input[] 的角色不受该型号支持 |
video_duration_invalid / video_resolution_invalid | 时长或分辨率超出该型号范围 |
audio_format_not_supported | 音频格式不受支持 |
file_required / file_purpose_not_supported | 文件上传缺少文件,或 purpose 与型号不匹配 |
use_owned_platform_resource | file_id、voice 等字段必须使用本平台签发的 file_tts_… / voice_tts_… |
voice_not_registered / voice_model_mismatch | 音色不是该型号的系统音色,或属于其他型号 |
utf8_text_required / text_file_limit / zip_* / embedding_* | 文本或压缩包文件不符合要求 |
system_one_* / cloudflare_* | System One 请求不符合协议,后缀说明具体原因,见 System One 指南 |
429 Too Many Requests#
error.code | 原因 |
|---|---|
resource_daily_limit | 文件上传(每账号每天 100 次)或音色创建(每天 20 次)已达上限 |
provider_http_429 | 厂商对平台的请求限流。未计费,稍后用新键重试 |
平台本身对推理请求没有按分钟计的频率限制,并发上限以 409 返回,见限制与配额。
厂商错误#
厂商拒绝请求时,错误码为 provider_http_<厂商状态码>:
| 厂商状态 | 平台返回 | 计费 |
|---|---|---|
| 4xx(参数错误、内容审核、限流等) | 同一个 4xx,附脱敏后的 message | 不计费,预留立即释放 |
| 5xx | 502 | 结果未知,调用进入待核对,预留暂不释放 |
provider_http_401 / provider_http_403 通常表示平台侧的厂商凭据或权限问题,请联系支持。
5xx#
| HTTP | error.code | 原因与处理 |
|---|---|---|
| 502 | execution_result_pending | 结果尚未确定(也用于未预期的内部错误,以及同一个幂等键换了 model 的请求)。用原键查询结果 |
| 502 | provider_response_pending_reconciliation | 厂商响应无法自动解析,已保存待核对。用原键查询结果 |
| 502 | provider_http_5xx | 厂商服务错误,见上表 |
| 503 | main_wallet_authorization_failed | 主站暂时不可用,见上文。用原键查询结果 |
| 503 | model_not_enabled | 型号暂停服务。发生在受理前,用原键查询会返回 404 |
| 503 | model_price_activation_pending | 型号价格正在更新,请求没有发往厂商,但这个幂等键已被占用。稍后用新键重试 |
| 503 | provider_not_configured / region_not_configured / execution_not_configured / media_not_configured | 平台侧配置暂不可用。先用原键查询:返回 404 表示没有受理,可稍后用原键重发;返回结果信封时按其状态处理 |
流式响应开始后发生的错误不会改变 HTTP 状态码,而是以 event: error 结束流,见流式输出。
在代码中处理错误#
import os
import uuid
import requests
ACCEPTED = {"request_already_accepted", "request_already_dispatched"}
key = str(uuid.uuid4())
try:
r = requests.post(
"https://api.tokentosea.com/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['TOKENTOSEA_API_KEY']}", "Idempotency-Key": key},
json={"model": "qwen3.8-flash", "messages": [{"role": "user", "content": "你好"}], "max_tokens": 64},
timeout=(10, 1300),
)
except requests.RequestException:
print("结果未知:用原幂等键查询 /v1/results/" + key)
else:
data = r.json() if "json" in r.headers.get("content-type", "") else {}
code = data.get("error", {}).get("code", "")
if r.status_code == 200:
print(data["choices"][0]["message"]["content"])
elif r.status_code == 202 or r.status_code >= 500 or code in ACCEPTED:
print(f"HTTP {r.status_code} {code}:未完成或结果未知,用原幂等键查询 /v1/results/{key}")
else:
print(f"HTTP {r.status_code} {code}:未执行,修正后用新的幂等键重新发起")import { randomUUID } from 'node:crypto';
const ACCEPTED = new Set(['request_already_accepted', 'request_already_dispatched']);
const key = randomUUID();
let response;
try {
response = await fetch('https://api.tokentosea.com/v1/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TOKENTOSEA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': key,
},
body: JSON.stringify({ model: 'qwen3.8-flash', messages: [{ role: 'user', content: '你好' }], max_tokens: 64 }),
});
} catch {
console.log(`结果未知:用原幂等键查询 /v1/results/${key}`);
}
if (response) {
const data = await response.json().catch(() => ({}));
const code = data.error?.code ?? '';
if (response.status === 200) {
console.log(data.choices[0].message.content);
} else if (response.status === 202 || response.status >= 500 || ACCEPTED.has(code)) {
console.log(`HTTP ${response.status} ${code}:未完成或结果未知,用原幂等键查询 /v1/results/${key}`);
} else {
console.log(`HTTP ${response.status} ${code}:未执行,修正后用新的幂等键重新发起`);
}
}完整的重试与查询实现见幂等与重试。
联系支持时请提供#
X-Request-Id(即幂等键)、结果信封中的 run_id、型号 ID、请求时间(含时区)、HTTP 状态码与 error.code。不要发送密钥明文。见获取支持。