错误码参考
JarvisClaw API 所有服务的完整错误码参考。包括 HTTP 状态码、x402 支付错误和服务特定错误码。
基础 URL: https://api.jarvisclaw.ai/v1
HTTP 状态码
| 状态码 | 名称 | 描述 | 解决方案 |
|---|---|---|---|
| 400 | Bad Request | 请求体格式错误或缺少必需参数。 | 检查请求格式和必填字段。 |
| 401 | Unauthorized | API Key 无效或缺失。 | 验证你的 API Key 是否正确且激活。 |
| 402 | Payment Required | 需要 x402 支付或 USDC 余额不足。 | 充值 USDC 钱包或检查支付签名。 |
| 403 | Forbidden | API Key 缺少该资源的权限。 | 在控制台检查 Key 权限。 |
| 404 | Not Found | 端点或资源不存在。 | 验证 URL 路径是否正确。 |
| 429 | Rate Limited | 时间窗口内请求过多。 | 退避并在 Retry-After 头指定时间后重试。 |
| 500 | Internal Server Error | 服务器意外故障。 | 指数退避重试;持续则联系支持。 |
| 502 | Bad Gateway | 上游供应商不可用。 | 重试;供应商可能暂时宕机。 |
| 503 | Service Unavailable | 服务过载或维护中。 | 等待几秒后重试。 |
错误响应体结构
有两种结构在流通,请都做兼容处理。
OpenAI 兼容的 relay 端点(/v1/chat/completions、/v1/messages、/v1/images/*、 /v1/audio/* 等):
{ "error": { "message": "...", "type": "...", "code": "..." } }AIP、钱包与 marketplace 端点:
{ "error": "可读的错误消息" }两个 SDK 都做了归一化 —— Python 的 APIError.message 和 Go 的 APIError.Message 会读取实际 到达的那种形态,原始响应体在 .body / .Body 上。
不要按错误码字符串分支
只有 relay 路径会返回 code,且取值取决于上游供应商返回了什么。AIP 与钱包端点只返回一个裸消息 字符串,完全没有 code。请按 HTTP 状态码和错误类型分支,把 code 当作诊断文本。
x402 支付失败
支付问题会以带 x402 报价体的 402 出现,或以携带 facilitator 拒绝原因的 402/502 出现。 常见原因:
| 原因 | 表现 | 解决方案 |
|---|---|---|
| USDC 余额不足 | 付费重试时返回 402 | 向钱包充值(Base 或 Solana) |
| 签名不匹配 | facilitator 校验失败 | 确认私钥对应 from 地址 |
| Nonce 重用 | 被重放保护拒绝 | SDK 每次尝试都生成新的随机 nonce |
| 授权过期 | 超过 maxTimeoutSeconds(300 秒)后被拒 | 重新签名重试;SDK 会自动处理 |
| 金额不匹配 | 校验阶段被拒 | 严格按 402 中的 amount 签名,不要取整 |
| 网络不受支持 | accepts 中没有可用选项 | 使用 Base(eip155:8453)或 Solana 主网 |
| Solana ATA 缺失 | Solana 路径被跳过 | 先接收一笔 USDC 转账以初始化代币账户 |
| 无法定价 | 503 price_unavailable | 上游价格探测失败,稍后重试 |
只有在网关已知 fee payer 时才会公布 Solana 选项;否则 accepts 只列 Base。详见 Agent 支付 (x402)。
常见失败场景
| 场景 | 状态码 | 说明 |
|---|---|---|
| 未知或已下线的模型 | 400 | 查询 GET /v1/models;智能路由别名必须带 auto/ 前缀 |
| 超出上下文窗口 | 400 | 精简历史或换用更大上下文的模型 |
| 内容过滤 | 400 / 任务 failed | 异步任务会返回 status: "failed" 且 retryable: false |
| 上游供应商错误 | 502 | 重试,或改用其他模型 |
| 触达并发上限 | 429 | Marketplace 服务对并发请求数有上限 |
| 异步任务仍在执行 | 200,status: "in_progress" | 继续轮询直到 completed 或 failed |
代码示例
# 检查 HTTP 状态和错误体
curl -s -w "\nHTTP_STATUS:%{http_code}" \
https://api.jarvisclaw.ai/v1/chat/completions \
-H "Authorization: Bearer $JARVISCLAW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}' \
| tee >(tail -1 | grep -o "HTTP_STATUS:[0-9]*") \
| head -n -1 | jq .
# 错误时响应体将包含:
# { "error": { "code": "invalid_model", "message": "..." } }
# 或 x402 错误:
# { "error": { "code": "insufficient_balance", "message": "..." } }import time
from jarvisclaw import (
OpenAI,
APIError,
AuthenticationError,
InsufficientBalanceError,
JarvisClawError,
RateLimitError,
)
# OpenAI 是兼容入口;ChatClient / JarvisClaw 用法相同。
client = OpenAI(api_key="sk-your-api-key")
def chat_with_retry(messages, model="openai/gpt-4o-mini", max_retries=3):
for attempt in range(max_retries):
try:
return client.chat.completions.create(
model=model,
messages=messages,
)
except AuthenticationError as e:
# 401 — API Key 无效,无需重试
print(f"认证失败: {e.message}")
raise
except InsufficientBalanceError as e:
# 402 — USDC 不足;充值后手动重试
print(f"余额不足: {e.message}")
print(f"错误码: {e.body.get('error', {}).get('code')}")
raise
except RateLimitError as e:
# 429 — 使用 Retry-After 退避
wait = e.retry_after or (2 ** attempt)
print(f"限流中。{wait}s 后重试…")
time.sleep(wait)
except APIError as e:
# 500 / 502 / 503 — 临时服务端错误
if e.status_code in (500, 502, 503) and attempt < max_retries - 1:
wait = 2 ** attempt
print(f"服务端错误 {e.status_code}。{wait}s 后重试…")
time.sleep(wait)
else:
# 400 / 403 / 404 或重试耗尽
code = e.body.get("error", {}).get("code", "unknown")
print(f"API 错误 [{e.status_code}] {code}: {e.message}")
raise
except JarvisClawError as e:
# x402 支付 / SDK 级错误
print(f"SDK 错误: {e}")
raise
raise RuntimeError("超过最大重试次数")package main
import (
"context"
"errors"
"fmt"
"time"
jarvisclaw "github.com/api-jarvisclaw/go-sdk/v2"
)
func chatWithRetry(
ctx context.Context,
client *jarvisclaw.Client,
messages []jarvisclaw.Message,
maxRetries int,
) (*jarvisclaw.ChatResponse, error) {
for attempt := range maxRetries {
resp, err := client.ChatCompletion(ctx, "openai/gpt-4o-mini", messages)
if err == nil {
return resp, nil
}
var authErr *jarvisclaw.AuthenticationError
if errors.As(err, &authErr) {
// 401 — API Key 无效,不重试
return nil, fmt.Errorf("认证失败: %w", err)
}
var balanceErr *jarvisclaw.InsufficientBalanceError
if errors.As(err, &balanceErr) {
// 402 — 充值 USDC 钱包
return nil, fmt.Errorf("余额不足: %w", err)
}
var rateErr *jarvisclaw.RateLimitError
if errors.As(err, &rateErr) {
// 429 — 退避
wait := time.Duration(1<<attempt) * time.Second
fmt.Printf("限流中。%s 后重试...\n", wait)
time.Sleep(wait)
continue
}
var apiErr *jarvisclaw.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 500, 502, 503:
// 临时服务端错误 — 指数退避
if attempt < maxRetries-1 {
wait := time.Duration(1<<attempt) * time.Second
fmt.Printf("服务端错误 %d。%s 后重试...\n", apiErr.StatusCode, wait)
time.Sleep(wait)
continue
}
default:
// 400 / 403 / 404 / upstream_error — 不可重试
code := apiErr.Body["error"]
return nil, fmt.Errorf("API 错误 [%d] %v: %s", apiErr.StatusCode, code, apiErr.Message)
}
}
// PaymentError / 其他 SDK 错误
return nil, fmt.Errorf("SDK 错误: %w", err)
}
return nil, fmt.Errorf("超过最大重试次数 (%d)", maxRetries)
}错误类型没有 Type 字段
Go 的 APIError 暴露 StatusCode、Message 和 Body —— 请按具体错误类型或状态码分支, 而不是某个字符串判别字段。AuthenticationError、RateLimitError、InsufficientBalanceError 都嵌入 APIError;PaymentError 嵌入 JarvisClawError。Python 侧层级一致 —— 详见 SDK → 错误处理。