対処できるエラー
Hyperouter のエラーはすべて、OpenAI のエラーオブジェクトと、対応する HTTP ステータスで返されます。OpenAI のエラーを処理するコードであれば、そのほとんどをすでに処理できます。このガイドでは、対処すべきものとそうでないものを整理し、最後にリトライのループを紹介します。
エラーオブジェクト
{
"error": {
"message": "n must be an integer from 1 to 128",
"type": "invalid_request_error",
"code": "invalid_body",
"param": "n"
}
}
| Field | 意味 |
|---|---|
message | 何が問題かを説明する文です。解析しないでください。 |
type | エラーの種類です。 |
code | 原因を示す安定した識別子です。このフィールドで判定してください。 |
param | 問題のあるリクエストのフィールド、または null です。 |
一部のエラーには generation_id が加わります。これは、まだ実行中、またはすでに実行されたジョブの ID です。GET /v1/generations/{id} でポーリングしてください。
対処すべきステータス
| ステータス | 意味 | 対処 |
|---|---|---|
400 | リクエストが無効です。code が原因を、param が該当のフィールドを示します。 | リクエストを修正してください。そのままでは再試行しないでください。 |
401 | API キーがない、または有効ではありません。 | キーを確認してください。 |
402 | insufficient_credits:残高またはキーの上限が、リクエストにかかりうる最大額をまかなえません。 | チャージするか、キーの上限を引き上げてください。 |
403 | アカウントが停止されている、または機能やモデルがアカウントで有効になっていません。 | サポートチケットを作成してください。 |
404 | そのような ID がない、他のアカウントの ID、または expires_at を過ぎた動画です。 | 再試行しないでください。 |
409 | 呼び出しを許可する状態にない、または Idempotency-Key が競合しています。 | Idempotency-Key で安全にリトライするを参照してください。 |
429 | すべてのプロバイダーが上限に達している、またはアカウントがレート制限を超えています。 | Retry-After の時間だけ待ってから、再試行してください。 |
500、501 | Hyperouter が失敗した、またはエンドポイントが実装されていません。課金されません。 | 500 は、下記のとおり注意して再試行してください。 |
503 | プロバイダーが失敗した、または時間内に応答しませんでした。 | 下記のとおり再試行してください。 |
よく遭遇する 3 つのコード
insufficient_credits(402)。チャットでは、メッセージに、まかなえるトークン数が示されます。max_tokensを下げると、リクエストにかかりうる最大額が下がります。チャージは、ダッシュボードでの手動の依頼です。GET /v1/credits を使うと、不足を事前に把握できます。model_not_enabled(403)。モデルを利用するには、アカウントへのアクセス許可が必要です。サポートチケットを作成して依頼してください。クレジットの確保も、プロバイダーへの送信も行われません。rate_limited(429)。アカウントが、1 分あたりのリクエスト数、または同時リクエスト数の上限を超えています。クレジットの確保も、転送も行われません。レスポンスには秒数を示すRetry-Afterヘッダーが付き、各段階はレート制限のセクションに掲載しています。
同じ系統に venue_busy(429)があります。チャットモデルのすべてのプロバイダーが、レートの上限に達している状態です。
502 や 504 ではなく 503 を返す理由
Hyperouter は 502 や 504 を返しません。これらは、エラーボディのない、エッジネットワークからの素のページとして届いてしまい、code を読み取れないためです。
ゲートウェイであればこれらを返す場面では、通常のエラーオブジェクトを持つ 503 が返り、ゲートウェイのステータスはレスポンスヘッダー X-Upstream-Status に入ります。プロバイダーが失敗した場合は 502、タイムアウトした場合は 504 です。どの種類の失敗かは code が示し、all_venues_failed、upstream_error、timeout のいずれかです。
HTTP/2 503
x-upstream-status: 504
失敗とタイムアウトを区別したい場合は、X-Upstream-Status を読み取ってください。ほとんどのコードでは、503 と code で十分です。
再試行してはいけない場合
再試行が常に安全とは限りません。再試行によって、2 つ目のジョブや 2 回目の課金が発生することがあります。Hyperouter は、そのようなレスポンスに x-should-retry: false を付けます。
- 同期画像の
503timeout。ジョブは継続し、成功した時点で課金されます。代わりにerror.generation_idをポーリングしてください。 - ジョブの作成後の
500。 409idempotency_key_reusedとidempotency_key_replayed。
チャットでは、リクエストを受け付けたプロバイダーが、それを実行中である可能性があります。その後プロバイダーが応答しなくなった場合、リクエストは別のプロバイダーには送信されません。コード timeout または upstream_error の 503 が返り、確保した額が課金されます。再送するかどうかを決める前に、GET /v1/generations/{id} で調べてください。
バックオフ付きのリトライのループ
429 と 503 を再試行し、Retry-After に従い、x-should-retry: false の場合は諦め、料金がかかるリクエストには Idempotency-Key を付けます。
import random import time import uuid import requests def post_with_retry(url, headers, body, attempts=5): headers = {**headers, "Idempotency-Key": str(uuid.uuid4())} # same key on every attempt for attempt in range(attempts): r = requests.post(url, headers=headers, json=body, timeout=120) if r.status_code < 400: return r.json() if r.headers.get("x-should-retry") == "false": r.raise_for_status() if r.status_code not in (429, 503) or attempt == attempts - 1: r.raise_for_status() wait = float(r.headers.get("Retry-After", 2 ** attempt)) time.sleep(wait + random.random()) # jitter
async function postWithRetry(url: string, body: unknown, attempts = 5) {
const headers = {
Authorization: `Bearer ${process.env.HYPEROUTER_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(), // same key on every attempt
};
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
if (res.ok) return res.json();
const retryable = [429, 503].includes(res.status) && res.headers.get("x-should-retry") !== "false";
if (!retryable || attempt === attempts - 1) throw new Error(`HTTP ${res.status}`);
const wait = Number(res.headers.get("Retry-After") ?? 2 ** attempt);
await new Promise((r) => setTimeout(r, (wait + Math.random()) * 1000));
}
}
チャットのリクエストでは、最初の試行が実際に実行されていた場合、再試行に対して 409 idempotency_key_replayed が返ります。これは、GET /v1/generations/{id} で記録を読み取り、再試行をやめる合図です。
OpenAI SDK は、408、409、429、5xx をすでに 2 回再試行し、x-should-retry: false にも従うため、ループが不要な場合もあります。
次のステップ
- エラーに、すべてのコードをステータスとともに掲載しています。
- チケットを作成するときは、リクエストの
idを添えてください。すべてのリクエストには引用できる ID がありますを参照してください。