OpenRouterで429が返っても、必ずしもOpenRouterアカウントの上限に達したとは限りません。選択した上流プロバイダー側でリクエストを制限している場合もあります。まずは失敗したレスポンスを1件、HTTPステータス、レスポンスヘッダー、JSONボディまで丸ごと保存してください。どの制限を対処すべきかは、ここから判断できます。
変更する前に、429レスポンスを1件確認する
クレジットを購入したり、APIキーを作り直したり、リトライを追加したりする前に、失敗の種類を切り分けましょう。上流プロバイダーから転送された文言が人間向けメッセージに含まれることがあるため、OpenRouterの型付きフィールドとレスポンスヘッダーのほうが確かな判断材料になります。
| 確認できる情報 | 原因として最も考えられる場所 | 次に行うこと |
|---|---|---|
HTTP 429に加え、X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Resetがある | OpenRouterプラットフォームの上限 | リセット時刻まで待ち、リクエスト頻度または同時実行数を下げる |
error.metadata.error_typeがrate_limit_exceededで、provider_codeなどのプロバイダー情報が含まれる | 上流プロバイダー | 待機する、別のプロバイダーを許可する、またはモデルフォールバックを使う |
Retry-Afterがある | 試行されたすべてのプロバイダーがリトライ待機時間を示している | 次の試行まで、その時間だけ待つ |
| HTTP 402 | 残高不足、またはキーごとのクレジット上限を使い切った | クレジットを追加するかキーの上限を変更する。リトライのバックオフでは解決しない |
HTTP 200の後、SSEエラーとfinish_reason: "error"が届く | ストリーミング開始後の失敗 | ストリーム全体を失敗として扱い、埋め込まれたエラー種別を調べる |
OpenRouterのエラーとデバッグのリファレンスでは、error.code、error.message、任意のerror.metadataから成るエンベロープを定義しており、error_type = "rate_limit_exceeded"もここに含まれます。また、正常レスポンスには通常X-RateLimit-*が含まれないことも記載されています。プロバイダーの過負荷はprovider_overloadedとして別に分類され、通常は503に対応します。
OpenRouter側の429を解消する
OpenRouter側の429は、アカウントとモデル区分に紐づくプラットフォームのクォータによって発生します。2026年7月31日に公式のレート制限ドキュメントで確認した時点では、末尾が:freeの無料モデルバリアントには、分単位と日単位の両方で制限があります。
| 無料モデルのクォータ | 現在の上限 |
|---|---|
| 1分あたりのリクエスト数 | 20 RPM |
| 累計クレジット購入額が$10未満の場合の1日あたりのリクエスト数 | 50 RPD |
| 累計クレジット購入額が$10以上の場合の1日あたりのリクエスト数 | 1,000 RPD |
制限ポリシーによると、アカウントやキーを追加しても、グローバルに管理される利用可能容量は増えません。有効なキーを差し替えても、プラットフォームのレート制限はリセットされません。
使用量とクレジット制限は、GET /api/v1/keyエンドポイントで確認できます。
curl https://openrouter.ai/api/v1/key \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
プラットフォーム由来の429なら、エラーレスポンスのリセットヘッダーを参照し、次の順で対策します。
- 即時リトライを止め、
X-RateLimit-Resetの時刻まで待つ。 - リクエスト毎秒数だけでなく、同時実行リクエスト数を減らす。並列ワーカーが一斉に動くと、最初の429をどのワーカーも確認する前に上限を超えることがあります。
- 共有リミッターの後ろに処理をキューイングし、すべてのワーカーが同時に起床してリトライしないようにする。
- ワークロードが無料モデルのクォータに収まらないなら、そのトラフィックを適切な有料モデルバリアントへ移す。
残高がマイナスの場合やキーごとのクレジット上限を使い切った場合は402になるはずです。一方、資金のあるアカウントでも、上流プロバイダーから429が返ることはあります。費用とクレジットについては、OpenRouter料金ガイドで別途解説しています。
「Provider Returned Error」の429を解消する
プロバイダーから返された429は、OpenRouterが上流の推論プロバイダーには到達したものの、その時点ではリクエストを受け付けてもらえなかったことを意味します。型付きのレート制限値とプロバイダーメタデータを確認してください。OpenRouterのクレジットを追加しても、そのプロバイダー側の処理能力は増えません。
公式の制限リファレンスによれば、エラーを返す前にルーティングが代替プロバイダーをすでに試している場合があります。また、試行されたすべてのプロバイダーがリトライの目安を返した場合はRetry-Afterが追加されます。実際の対処は次のとおりです。
- 同じリクエストをすぐ再生成するのではなく、
Retry-Afterを守る。 - 混雑した経路が1つしか残らないほど厳しいプロバイダー制限を設定しているなら、条件を緩める。
- そのリクエストでプロバイダーフォールバックが許可されていることを確認する。
- 厳密に同じモデルであることよりタスク完了が重要なら、モデルフォールバックを設定する。
クレジットを入れているZedユーザーがmoonshotai/kimi-k2:freeで上流の制限に遭遇し、キーを作り直しても改善しませんでした。Zedのコントリビューターは次のように説明しています。
「これはZedのエラーではありません。OpenRouterが、利用している上流プロバイダーによってレート制限を受けていると伝えているのです。」出典: zed-industries/zed issue #35153
Retry-Afterが短時間を示しているなら待機しましょう。厳密に同じモデルを使い続けるよりもタスクを完了することが優先なら、無料モデルのフォールバックを使ってください。
Janitor AI、Zed、SillyTavernでエラーが出る場合
生のエラーを保存し、何度も再生成するのは避けてください。プロバイダー側の失敗では、モデルまたは許可するルートを変更します。キーを再入力するのはクライアント内の保存状態を直すときだけであり、利用可能容量をリセットする効果はありません。
429ループを起こさないリトライ設計
リトライ対象はレート制限エラーだけに絞り、試行回数には上限を設けます。サーバーから待機時間を指定されている場合は、それを優先してください。リトライの目安がない場合は、上限付き指数バックオフにジッターを加えます。並列クライアントが同期して次のバーストを起こすのを防ぐためです。
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function retryDelayMs(response, attempt) {
const retryAfter = response.headers.get("retry-after");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);
const dateMs = Date.parse(retryAfter);
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
}
const capMs = 30_000;
const exponentialMs = Math.min(capMs, 1000 * 2 ** attempt);
return Math.random() * exponentialMs; // Full jitter
}
async function createChatCompletion(body, maxAttempts = 4) {
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(
"https://openrouter.ai/api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
},
);
const raw = await response.text();
let payload;
try {
payload = raw ? JSON.parse(raw) : null;
} catch {
payload = null;
}
if (response.ok) return payload;
const isRateLimit =
response.status === 429 ||
payload?.error?.metadata?.error_type === "rate_limit_exceeded";
if (!isRateLimit || attempt === maxAttempts - 1) {
const error = new Error(payload?.error?.message || raw || `HTTP ${response.status}`);
error.status = response.status;
error.details = payload?.error;
throw error;
}
await sleep(retryDelayMs(response, attempt));
}
}
この関数が扱うのは非ストリーミングレスポンスです。多数の待機中ワーカーが一斉に再開しないよう、共有キューまたはトークンバケットによる同時実行制御は関数の外側に置いてください。
HTTP 200でServer-Sent Eventsが始まった後は、ステータスを429へ変更できません。OpenRouterのエラーリファレンスによれば、その後の失敗はストリーム内でエラーとして届き、finish_reason: "error"で終了します。完了処理は失敗として扱い、埋め込まれた種別がrate_limit_exceededの場合にだけリトライしてください。アプリケーションが部分結果を明示的にサポートしていない限り、蓄積済みのテキストを成功結果として返してはいけません。
よくある質問
OpenRouterの「429 provider returned error」とは何ですか?
上流の推論プロバイダーが、自身のレート制限または処理能力の制限によりリクエストを拒否したことを意味します。error.metadata.error_typeとプロバイダーメタデータで確認してください。
クレジットが残っているのにOpenRouterで429になるのはなぜですか?
クレジットのあるアカウントでも、プロバイダー側の429は発生します。残高不足またはキーごとのクレジット上限は、通常は429ではなく402です。
OpenRouterのAPIキーを新しく作るとレート制限はリセットされますか?
いいえ。キーを追加してもグローバルに管理される制限は増えません。キーの差し替えが必要なのは、認証やクライアント側の保存状態を修正するときだけです。
OpenRouterをリトライするまで、どれくらい待つべきですか?
Retry-Afterがあれば、その値を使います。プラットフォームの制限ならX-RateLimit-Resetを参照してください。どちらもない場合は、上限付き指数バックオフとジッターを使い、最大試行回数は少なく設定します。
OpenRouterはHTTP 200を返した後でも429で失敗することがありますか?
はい。ストリーミングがすでに始まっている場合です。HTTPステータスは200のままですが、SSEストリームがエラーを報告し、finish_reason: "error"で終了します。レート制限だったかどうかは、埋め込まれたエラー種別を確認して判断してください。