关于 venice-errors
venice-errors 是 Venice API 的错误与重试参考,面向需要处理 API 响应的开发者。它按状态码梳理错误结构、限流信息及对应处理方式,涵盖 x402 认证与支付错误。
主要功能
- 01归纳常见错误响应结构
- 02按状态码说明错误含义
- 03介绍限流响应头与错误预算
- 04说明 x402 支付和签名错误
- 05提供重试或修正建议
适用场景
- 01为 API 客户端编写错误处理
- 02区分可重试与不可重试错误
- 03排查 x402 认证或余额问题
- 04处理限流与模型过载响应
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ veniceai/ skills --skill venice-errors安装后在 Claude Code 中输入/venice-errors确认已加载。
详细介绍
Venice 错误与重试
Venice 的大多数错误都采用 { "error": "<message>" } 格式,但有几种情况会附带结构化信息。了解错误的具体格式,就能知道该如何处理。
错误响应体格式
1. StandardError — 简单消息
4xx/5xx 错误的默认格式。
{ "error": "Authentication failed" }
2. DetailedError — 架构验证失败(400)
请求不符合 Venice 自身的架构时,details 是一个嵌套树(按字段递归列出 _errors),而 issues 是扁平的问题列表。某些图像、视频和上游错误则会将 details 作为普通字符串返回,因此遍历前请先检查其类型。
{
"error": "Invalid request parameters",
"details": {
"_errors": [],
"type": { "_errors": ["Invalid enum value. Expected 'asr' | 'decision' | … , received 'bogus'", "Invalid enum value. Expected 'all' | 'code', received 'bogus'"] }
},
"issues": [
{ "code": "invalid_union", "unionErrors": [ … ], "path": ["type"], "message": "Invalid input" }
]
}
(这是对 GET /models?type=bogus 的实时响应。)
许多 400 错误采用普通的 StandardError 格式,请同时处理这两种情况。显示 details / issues;不要重试。
3. OpenAI 风格的上下文溢出(400,聊天)
{
"error": {
"message": "Your request exceeds the model's maximum context. Please reduce your prompt or completion length.",
"type": "invalid_request_error",
"param": "messages",
"code": "context_length_exceeded"
}
}
请注意,此处的 error 是一个对象,因此 OpenAI SDK 可以识别它。message 是 Venice 能提取时使用的提供方措辞,否则就是上方的文本;请根据 code 而不是 message 进行判断。缩短提示词或降低 max_completion_tokens。
4. 上游提供方拒绝请求(400)
请求通过 Venice 的架构验证,但模型提供方拒绝请求时,Venice 会返回提供方的消息,并在会跟踪请求 ID 的路由上附带 request_id(例如聊天路由;/decisions 不会附带):
{ "error": "<provider's validation message>", "request_id": "…" }
FastAPI 风格的验证错误(例如 POST /decisions 背后的 TypeSafe 提供方返回的 422)会以 400 返回,其中最多包含五条 field.path: message,并以 ; 连接。如果 Venice 无法提取消息,你会收到 "Invalid request parameters. For assistance, please reach out to [email protected]";若存在请求 ID,后面还会附加 " and reference request ID: <id>"。这些错误会计入聊天 / responses 中宽松的不支持功能额度(参见错误额度)。修正输入;联系支持时请提供 request_id。
5. ContentViolationError — 内容政策错误(422)
{
"error": "Your prompt violates the content policy of Venice.ai or the model provider",
"suggested_prompt": "A cinematic instrumental track inspired by stormy weather and dramatic tension."
}
聊天、responses、图像编辑和多重编辑以及音频生成都会返回此错误。/image/generate 不使用此错误(被拦截的图像会以 200 状态返回,并附带 x-venice-is-content-violation: true),而视频内容政策拒绝会在 /video/retrieve 返回,而不是在排队时返回。suggested_prompt 仅由 /audio/queue 和 /audio/retrieve 返回;如果存在,且用户同意,可使用它重试一次。其他 422 错误包括 "Your input was blocked by content moderation." 和媒体验证失败(图像过大、宽高比错误、音频 / 视频时长超出范围、ASR 无法处理该音频)。
6. ProviderContentPolicyError — /video/retrieve 的 422
{
"error": {
"message": "The selected model provider rejected this request due to its content policies. Credits have been refunded. Try using <model> instead.",
"type": "provider_content_policy",
"credits_refunded": true,
"recommended_model": "<model id>"
}
}
检查 credits_refunded;也可以使用 recommended_model 重新排队。
7. PayloadTooLargeError — 413
{ "code": "PAYLOAD_TOO_LARGE", "error": "File exceeds the maximum allowed size of 25 MB." }
8. x402 402 响应体
402 有两种形式。两种形式都会设置 PAYMENT-REQUIRED 请求头。无凭据形式会在所有需要凭据的路由上返回,包括仅限 Bearer 的路由(/api_keys*、/billing/*、/characters*),这些路由不适用其中的支付选项。
完全没有凭据 - x402 v2 发现(不是 401):
{
"x402Version": 2,
"error": "Authentication required",
"resource": { "url": "https://api.venice.ai/api/v1/chat/completions", "description": "Venice API", "mimeType": "application/json" },
"accepts": [ { "scheme": "exact", "network": "eip155:8453", "…": "…" }, { "scheme": "exact", "network": "solana", "…": "…" } ],
"extensions": { "sign-in-with-x": { "info": { "domain": "api.venice.ai", "statement": "Sign in to Venice AI", "…": "…" }, "supportedChains": [ … ] } },
"authOptions": {
"apiKey": { "header": "Authorization: Bearer YOUR_API_KEY", "getKey": "https://venice.ai/settings/api", "docs": "…" },
"x402Wallet": { "header": "SIGN-IN-WITH-X", "legacyHeader": "X-Sign-In-With-X", "topUp": "POST /api/v1/x402/top-up", "docs": "…" }
}
}
已登录钱包余额低于最低限额 $0.10 - 根据 code: "PAYMENT_REQUIRED" 进行区分:
{
"error": "Payment required",
"code": "PAYMENT_REQUIRED",
"reason": "insufficient_balance",
"currentBalanceUsd": 0.01,
"minimumBalanceUsd": 0.1,
"description": "Venice API",
"suggestedTopUpUsd": 10,
"minimumTopUpUsd": 5,
"supportedTokens": ["USDC"],
"supportedChains": ["base", "solana"],
"topUpInstructions": {
"step1": "POST /api/v1/x402/top-up with no payment header to get payment requirements",
"step2": "Choose a payment option from accepts and sign a USDC transfer authorization using the x402 SDK (createPaymentHeader)",
"step3": "POST /api/v1/x402/top-up with the signed X-402-Payment header",
"receiverWallet": "0x…",
"tokenAddress": "0x…",
"tokenDecimals": 6,
"network": "eip155:8453",
"minimumAmountUsd": 5
},
"siwxChallenge": { "info": { … }, "supportedChains": [ … ] }
}
topUpInstructions 仅说明 Base 通道;如需通过 Solana 支付,请从 POST /x402/top-up 读取 accepts[](并发送 PAYMENT-SIGNATURE,这是规范请求头 - X-402-Payment / X-PAYMENT 仍然可用)。PAYMENT-REQUIRED 请求头是 base64 编码的 x402 paymentRequired 对象(x402Version、error、resource、accepts[]、extensions),而不是响应体。请参阅 venice-x402。
API 密钥的 402 响应是纯文本:{ "error": "Insufficient USD or Diem balance to complete request. Visit https://venice.ai/settings/api to add credits." },或者针对每个密钥的支出限额变体(“API key DIEM spend limit exceeded…” / “API key USD spend limit exceeded…”)。当钱包的额度高于 $0.10 下限,但不足以支付此请求的报价时(例如 /video/queue、/audio/queue),也可能收到同样的纯文本“Insufficient USD or Diem balance…”响应体 - 充值后重试。
9. x402 登录失败(401)
在推理路由上,错误的 SIGN-IN-WITH-X 会返回 { "error": "<message>", "code": "X402_SIGN_IN_…" }(例如 X402_SIGN_IN_EXPIRED、X402_SIGN_IN_NONCE_REUSED)。/x402/balance 和 /x402/transactions 会返回通用的 { "error": "Invalid Sign-in-with-x signature" }。所有代码请参阅 venice-auth。
状态码对照表
| 状态码 | 典型响应正文 | 含义 | 处理方法 |
|---|---|---|---|
400 | DetailedError、StandardError、上下文溢出对象,或上游 { error, request_id } | 输入格式错误、缺少 model 或其值不是字符串(纯文本错误为 "model is required" / "model must be a string")、此模型不支持的选项、提供商拒绝请求、JSON 无效("Invalid JSON request"),或 POST 请求的 Content-Type 既不是 JSON 也不是 multipart("'Content-Type' must be 'application/json'")。如果向推理路由而非 /x402/top-up 发送 x402 支付标头,也会返回 PAYMENT_HEADER_NOT_ACCEPTED。 | 修正后重新发送。不要重试。 |
401 | StandardError 或 { error, code } | API 密钥未知、已过期或已撤销("Authentication failed")、在仅限管理员的路由上使用了非 ADMIN 密钥("Admin API key required")、SIWX 错误,或出现 "This model is only available to Pro users"(使用 Pro 专属模型的 API 密钥账户没有付费套餐)。 | 修正凭据或套餐。不要重试。 |
402 | 参见形态 8 | 未提供凭据(发现阶段)、钱包余额过低,或 API 密钥账户 / 密钥的支出限额已用尽。 | x402:充值后重试。API 密钥:添加额度或提高密钥的限额。 |
403 | StandardError | 有权限但被阻止:模型在你所在的国家/地区被屏蔽(regionRestrictions)、密钥的 modelPrivacy 禁止使用该模型、API 访问已禁用、SIWX 钱包 ≠ 路径中的钱包。 | 不要重试。 |
404 | StandardError | 未知模型("Specified model not found: …",有时会附带建议或 "has been deprecated. Please use …" 提示)、未知角色、媒体已过期。 | 修正 ID。 |
409 | { error: { code: "needs_consent", message }, consent_flow, face_media_roles, consent, docs_url }(视频)或 { error, message, details }(x402) | /video/queue 需要用户同意(仅未列出的模型 ID 会要求;已列出的模型不会要求),或 x402 充值已处理或仍在结算中(error 中包含代码,例如 "PAYMENT_IN_PROGRESS"——请稍后重试)。 | 参见 venice-video / venice-x402。 |
410 | StandardError | 端点已停用(GET /billing/usage、POST /video/transcriptions)。消息中会注明替代端点。 | 迁移。绝不要重试。 |
413 | PayloadTooLargeError | JSON 正文超过 35 MB("Request body exceeds the maximum allowed size."),或 multipart 文件超过 25 MB。 | 缩小上传内容。 |
415 | StandardError | 少见情况:/image/multi-edit 请求正文为空,或请求正文使用了服务端无法解码的 Content-Encoding / 字符集("Request encoding is not supported")。任何路由上的 Content-Type 错误都会返回 400。 | 修正标头。 |
422 | ContentViolationError、ProviderContentPolicyError 或 StandardError | 内容策略违规,或媒体无法处理(尺寸、时长、音频无法读取)。 | 修改提示词或媒体。若提供了 suggested_prompt,可重试一次。 |
429 | StandardError 或 { error, code } | 请求 / 令牌速率限制、错误预算耗尽、模型过载、x402 并发限制(X402_CONCURRENCY_LIMIT,每个钱包最多 5 个并发请求),或特定路由的限流器(加密货币 RPC、/x402/*、/tee/*、已停用的端点)。 | 参见下方的速率限制说明。 |
500 | StandardError | 意外故障。 | 采用退避策略后重试。 |
502 | StandardError | 上游故障(TTS、ASR、TEE、视频获取)。 | 采用退避策略后重试。 |
503 | StandardError | 模型离线或已达容量上限。 | 采用退避策略;考虑使用备用模型。 |
504 | StandardError | 请求耗时过长。大多发生于非流式聊天。 | 使用 stream: true 或缩小请求。 |
速率限制及其标头
有三组互相独立的标头——它们共享前缀,但单位不同,因此请按完整名称准确识别:
| 标头 | 发出方 | 重置单位 |
|---|---|---|
x-ratelimit-limit-requests、x-ratelimit-remaining-requests、x-ratelimit-reset-requests(以及 -tokens 变体) | 推理路由上的模型速率限制(按账户、模型分别计算,限制每分钟/每天的请求数和每分钟的令牌数) | Unix 毫秒 |
x-ratelimit-remaining、x-ratelimit-resets | 错误预算,出现在大多数需要凭证的路由响应中(不包括无凭证时的 402) | Unix 毫秒 |
X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset | /crypto/rpc/{network},仅在触发其每分钟上限时返回的 429 响应中出现 | Unix 秒 |
模型限制触发的 429 会返回 "Rate limit exceeded"。请使用 GET /api_keys/rate_limits 预先查询额度(仅限 Bearer 密钥)。历史触发记录可通过 GET /api_keys/rate_limits/log 查看,此接口需要 ADMIN 密钥——INFERENCE 密钥会收到 401 "Admin API key required"(venice-api-keys)。
各路由的限制器返回的 429 不带这些标头:/x402/top-up(每个 IP 每分钟 10 次)、/x402/balance(每个钱包每分钟 30 次)和 /x402/transactions(每个钱包每分钟 20 次)会返回 "Rate limit exceeded. Please try again later.";/tee/*(每个 IP 每分钟 10 次)会返回 "Rate limit exceeded.";已停用的端点允许每个 IP 每分钟 60 次。
上游过载:返回带有 Retry-After 的 429(单位为秒,默认 30),以及类似 "The model is currently overloaded. Please try again later." 的消息。请遵循 Retry-After。
错误预算
失败请求受到的速率限制比成功请求更严格:
| 预算 | 阈值 | 计数范围 | 记录为 |
|---|---|---|---|
| 失败请求 | 每 30 s 50 次 | 任意 4xx,429 除外(5xx 不计数) | FAILED_REQUESTS |
| 不支持功能的请求 | 每 30 s 200 次,仅限 /chat/completions 和 /responses | 请求模型执行其不具备的功能,或服务提供方拒绝其他方面有效的请求 | UNSUPPORTED_FEATURE_REQUESTS |
计数桶按 API 密钥(x402 按 IP)、model 和 OpenAI 的 user 字符串划分;分块上传无法及时提取 model/user,因此会共用该密钥(或 IP)的计数桶。计数桶耗尽后,其中的每个请求在重置前都会收到 429,并附带:
Too many failed attempts (> 50) resulting in a non-success status code. Please wait 30 seconds and try again. See https://docs.venice.ai/api-reference/rate-limiting for more information.
不支持功能的计数桶会使用相同措辞,但阈值为 > 200。因此,盲目重试 400/401/402 的客户端会导致自身被锁定。遇到不可重试的错误时请停止重试。(无凭证时的 402、Content-Type 和无效 JSON 导致的 400,以及 35 MB JSON 请求体导致的 413,都会在检查预算前被拒绝,因此不计入预算。)
重试策略
切勿重试
400、401、403、404、410、413、415——请修正请求、凭证或端点。
修改后重试
402且code: "PAYMENT_REQUIRED"——在用户消费上限内通过/x402/top-up充值(参见venice-x402),然后重试。- 带有
x402Version的402(无凭证)——添加Authorization: Bearer …,或在支持钱包的路由上使用SIGN-IN-WITH-X。仅限 Bearer 的路由(/api_keys*、/billing/*、/characters*)会以401拒绝 SIWX;请在这些路由上发送 Bearer 密钥。 - 使用钱包身份验证进行的任何重试都需要新签名的
SIGN-IN-WITH-X标头——每个 nonce 只能接受一次,因此重新发送原标头会导致X402_SIGN_IN_NONCE_REUSED。 - API 密钥收到
402时——向用户显示该错误。 422且带有suggested_prompt——使用更安全的提示词重试一次。
使用退避策略重试
429- 如果存在Retry-After,则等待指定时间;否则等待到相关重置标头指示的时间,并加入随机抖动。500/502/503/504- 使用指数退避(0.5 s、1 s、2 s、4 s、8 s),最长约 30 s,最多重试 3-5 次。- 异步队列(
/video/queue、/audio/queue、/audio/voice-changer/queue)可能会在任务完成前计费(API 密钥调用会在入队时预扣费用)。如果队列响应丢失,请轮询retrieve,而不是重新入队。仅/crypto/rpc/{network}支持Idempotency-Key。
重试循环参考
const sleep = (ms: number) => new Promise(r => setTimeout(r, ms))
function waitMs(res: Response, fallback: number): number {
const retryAfter = Number(res.headers.get('retry-after'))
if (retryAfter > 0) return retryAfter * 1000
const msReset = Number(res.headers.get('x-ratelimit-reset-requests') ?? res.headers.get('x-ratelimit-resets'))
if (msReset > 0) return Math.max(msReset - Date.now(), fallback)
const secReset = Number(res.headers.get('x-ratelimit-reset')) // crypto RPC
if (secReset > 0) return Math.max(secReset * 1000 - Date.now(), fallback)
return fallback
}
// fn must build a fresh SIGN-IN-WITH-X header on every call; nonces are single-use.
async function callVenice<T>(fn: () => Promise<Response>): Promise<T> {
const maxRetries = 5
let delay = 500
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fn()
if (res.ok) return res.json() as Promise<T>
const body = await res.clone().json().catch(() => ({}))
const message = typeof body.error === 'string' ? body.error : body.error?.message ?? 'Venice error'
const fail = () => Object.assign(new Error(message), { status: res.status, body })
if ([400, 401, 403, 404, 410, 413, 415, 422].includes(res.status)) throw fail()
if (res.status === 402) {
// topUpAllowed must enforce the user's cap and check GET /x402/balance first.
if (body.code === 'PAYMENT_REQUIRED' && attempt === 0 && (await topUpAllowed())) {
await topUpX402(Math.min(body.suggestedTopUpUsd, USER_TOP_UP_CAP_USD))
continue
}
throw fail()
}
if ((res.status === 429 || res.status >= 500) && attempt < maxRetries) {
await sleep((res.status === 429 ? waitMs(res, delay) : delay) + Math.random() * 250)
delay = Math.min(delay * 2, 30_000)
continue
}
throw fail()
}
throw new Error('Exceeded max retries')
}
流式错误
如果 /chat/completions 流在发送标头后失败,HTTP 状态仍为 200,错误会以内嵌方式返回,随后是终止符:
data: {"error":{"message":"…","type":"server_error","code":"model_overloaded","param":null,"retry_after":30}}
data: [DONE]
过载错误使用 type: "server_error"、code: "model_overloaded",并可能携带 retry_after(秒);其他上游故障使用 type: "api_error",其 code 为 "upstream_error" 或特定代码(例如 e2ee_attestation_stale)。应将此事件视为终止事件。
请求 ID 关联
聊天请求的上游拒绝响应正文包含 request_id,而 /crypto/rpc/{network} 会在代理响应中设置 X-Request-ID 标头。提交支持工单时,请附上其中任一项(以及响应标头中的 x-venice-version)。其他路由不保证提供请求 ID,因此也请保留自己的客户端关联 ID。
常见注意事项
/x402/top-up返回的、不带支付标头的402响应是预期的发现响应。- 推理路由返回
402(而非401)通常意味着你完全没有发送身份验证标头。 - 不带后缀的
x-ratelimit-remaining表示错误预算,而非请求配额。 429可能由多种限制器触发(模型限制、错误预算、过载、x402 并发数、单路由上限)——请先阅读消息和标头,再决定等待多久。- 架构验证失败导致
400时,DetailedError.details是嵌套的_errors树,而非扁平映射;某些图像、视频或上游故障会将其作为普通字符串发送。遍历前请检查其类型。 - 在 SSE 流中,
data: [DONE]表示流已结束(错误块之后也一样),而非保活信号。