跳至主要內容

錯誤與錯誤碼

統一的錯誤 JSON 格式、完整錯誤碼清單,以及重試與處理策略。

錯誤與錯誤碼

所有錯誤都回傳非 2xx 的 HTTP 狀態碼,body 一律是以下結構:

{
  "error": {
    "code": "insufficient_credit",
    "message": "Your credit balance is insufficient for this request."
  }
}

code 是穩定的機器可讀字串,請以它做程式判斷;message 是人類可讀說明,措辭可能隨時調整,不要拿來做條件判斷。

錯誤碼清單

HTTPcode意義如何處理
400invalid_request請求格式錯誤:缺少必填欄位、JSON 無法解析、參數型別或範圍不對。修正請求。重試沒有意義。
401unauthorized缺少 Authorization 標頭,或格式不是 Bearer <key>。補上正確的標頭。
401invalid_api_key金鑰不存在、已刪除,或格式錯誤。檢查金鑰是否完整、有沒有多餘空白,或到 Dashboard 重建。
403api_key_disabled金鑰已被停用。到 Dashboard 重新啟用,或改用其他金鑰。
403model_not_allowed模型存在,但不在此金鑰的白名單內。調整金鑰的模型白名單,或改用允許的模型。
404model_not_found平台上沒有這個模型 ID。以 GET /v1/models 確認正確 ID。注意需要 provider/model 前綴。
402insufficient_credit帳戶餘額不足以支付這次請求。到 Dashboard 儲值。
402spend_limit_reached已達到此金鑰的每月花費上限。調高上限,或等次月自動重置。
429rate_limited請求速率超過限制。依 Retry-After 退避後重試。見 速率限制。
502upstream_error上游供應商回傳錯誤、逾時,或暫時無法使用。可安全重試,建議指數退避;或改用備援模型。

範例

HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "error": {
    "code": "spend_limit_reached",
    "message": "This API key has reached its monthly spend limit of $50.00."
  }
}
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "model_not_found",
    "message": "Model 'gpt-4o' does not exist. Did you mean 'openai/gpt-4o'?"
  }
}

是否該重試

類別錯誤碼重試?
用戶端錯誤invalid_request、model_not_found否。先修正程式。
認證問題unauthorized、invalid_api_key、api_key_disabled、model_not_allowed否。需要人為處理。
帳務問題insufficient_credit、spend_limit_reached否。需要儲值或調整上限。
暫時性問題rate_limited、upstream_error是。指數退避加抖動。

處理錯誤(Python)

openai SDK 會把非 2xx 轉成例外,錯誤 body 放在 err.response.json()。

import os
import time

import httpx
from openai import OpenAI, APIStatusError

client = OpenAI(
    base_url="https://api.alphacurve.io/v1",
    api_key=os.environ["INFERENCE_API_KEY"],
    timeout=httpx.Timeout(60.0),
)

RETRYABLE = {"rate_limited", "upstream_error"}

def complete(**kwargs):
    for attempt in range(5):
        try:
            return client.chat.completions.create(**kwargs)
        except APIStatusError as err:
            try:
                code = err.response.json()["error"]["code"]
            except Exception:
                code = "unknown"

            if code not in RETRYABLE:
                raise

            retry_after = err.response.headers.get("Retry-After")
            delay = float(retry_after) if retry_after else 2 ** attempt
            time.sleep(delay)

    raise RuntimeError("retries exhausted")

處理錯誤(Node / TypeScript)

import OpenAI, { APIError } from "openai";

const client = new OpenAI({
  baseURL: "https://api.alphacurve.io/v1",
  apiKey: process.env.INFERENCE_API_KEY!,
});

const RETRYABLE = new Set(["rate_limited", "upstream_error"]);

async function complete(
  params: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming,
) {
  for (let attempt = 0; attempt < 5; attempt++) {
    try {
      return await client.chat.completions.create(params);
    } catch (err) {
      if (!(err instanceof APIError)) throw err;

      const code = (err.error as { code?: string } | undefined)?.code ?? "unknown";
      if (!RETRYABLE.has(code)) throw err;

      const wait = 2 ** attempt * 1000 + Math.random() * 250;
      await new Promise((r) => setTimeout(r, wait));
    }
  }
  throw new Error("retries exhausted");
}

用 curl 除錯

加上 -i 就能同時看到狀態碼、標頭與 body:

curl -i https://api.alphacurve.io/v1/chat/completions \
  -H "Authorization: Bearer $INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "does-not-exist", "messages": [] }'

回報問題時,請附上回應中的 id(若有)、code、發生時間與所用模型,我們才能快速定位。

串流中的錯誤

串流一旦開始,HTTP 狀態碼就已經是 200。若之後才失敗,錯誤會以一筆 SSE 事件送出:

data: {"error":{"code":"upstream_error","message":"Upstream provider timed out."}}

data: [DONE]

因此串流的解析程式除了處理 choices,也必須檢查 chunk 裡有沒有 error 欄位。