429/容量エラー:アカウントローテーションの正しい期待とモデル容量枯渇の誤解
学んだ後できること
- 「クォータ不足」と「アップストリームレート制限」を正しく区別し、誤判を避けられる
- Antigravity Tools の自動ローテーションメカニズムと期待される動作を理解できる
- 429 エラーに遭遇したとき、問題を素早く特定し、設定を最適化できる
現在の悩み
- 429 エラーが返ってくると、誤って「モデルに容量がない」と思う
- 複数のアカウントを設定しているのに、依然として頻繁に 429 に遭遇し、設定問題かアカウント問題かわからない
- システムがいつ自動的にアカウントを切り替えるのか、いつ「詰まる」のかが不明確
コアコンセプト
429 エラーとは?
429 Too Many Requests は HTTP ステータスコードです。Antigravity Tools では、429 は「リクエストが多すぎる」だけでなく、クォータ枯渇、モデルの一時的な過負荷など「あなたが一時的に使用できない」信号のカテゴリを表します。
プロキシは 429 の原因を識別しようとします
プロキシはレスポンスボディから error.details[0].reason または error.message を解析し、429 を大まかにいくつかのタイプに分けます(実際は返り値に依存します):
| プロキシ識別タイプ | 一般的な reason / 手がかり | 典型的な特徴 |
|---|---|---|
| クォータ枯渇 | QUOTA_EXHAUSTED / テキストに exhausted、quota を含む | クォータが更新されるまで待つ必要がある可能性 |
| レート制限 | RATE_LIMIT_EXCEEDED / テキストに per minute、rate limit、too many requests を含む | 通常は数十秒レベルのクールダウン |
| モデル容量不足 | MODEL_CAPACITY_EXHAUSTED / テキストに model_capacity を含む | 一般的には一時的な過負荷で、後で回復可能 |
| 不明 | 解析不能 | デフォルトクールダウン戦略に従う |
Antigravity Tools の自動処理
一回のリクエストで 429(および一部の 5xx/過負荷状態)に遭遇したとき、プロキシは通常サーバー側で 2 つのことを行います:
- クールダウン時間を記録:このエラーを
RateLimitTrackerに書き込み、後続のアカウント選択時に「まだクールダウン中」のアカウントを積極的に回避する - 再試行内でアカウントをローテーション:Handlers は単一リクエスト内で複数回の試行を行い、再試行時に
force_rotate=trueとなり、TokenManager が次の利用可能なアカウントを選択するようにトリガーする
アカウントを切り替えたかどうかをどう知るか
リクエストボディが変わらなくても、レスポンスには通常 X-Account-Email(および X-Mapped-Model)が含まれます。これを使って「今回のリクエストがどのアカウントを使ったか」を検証できます。
いつ 429 エラーに遭遇するか
シナリオ 1:単一アカウントでリクエストが速すぎる
現象:アカウントが 1 つだけでも、短時間に大量のリクエストを送ると 429 がトリガーされる
原因:各アカウントには独自のレート制限(RPM/TPM)があり、超えると制限される
解決:
- アカウント数を増やす
- リクエスト頻度を下げる
- 固定アカウントモードを使って分散させる(「固定アカウントモード」を参照)
シナリオ 2:すべてのアカウントが同時にレート制限される
現象:複数のアカウントがあるのに、すべてのアカウントが 429 を返す
原因:
- アカウント総数があなたのリクエスト頻度を支えるのに不十分
- すべてのアカウントがほぼ同時にレート制限/過負荷をトリガーした
解決:
- さらにアカウントを追加
- スケジューリングモードを「パフォーマンス優先」に調整(スティッキーセッションと 60 秒ウィンドウ再利用をスキップ)
- クォータ保護が利用可能なアカウントを誤って除外していないか確認
シナリオ 3:アカウントがクォータ保護で誤判定される
現象:あるアカウントのクォータは十分にあるのに、システムがずっとそれをスキップする
原因:
- クォータ保護が有効で、閾値が高すぎる
- そのアカウントの特定モデルクォータが閾値より低い
- アカウントが手動で
proxy_disabledとマークされている
解決:
- クォータ保護設定を確認(Settings → Quota Protection)、使用強度に応じて閾値と監視モデルを調整
- アカウントデータで
protected_modelsを確認し、保護戦略でスキップされているか確認
手順通りに進める
第 1 ステップ:429 エラータイプを識別
なぜか:異なるタイプの 429 エラーは異なる処理方法が必要
Proxy Monitor で 429 エラーのレスポンスボディを確認し、2 種類の情報に焦点を当てる:
- 原因:
error.details[0].reason(例:RATE_LIMIT_EXCEEDED、QUOTA_EXHAUSTED)またはerror.message - 待ち時間:
RetryInfo.retryDelayまたはdetails[0].metadata.quotaResetDelay(存在する場合)
{
"error": {
"details": [
{
"reason": "RATE_LIMIT_EXCEEDED",
"metadata": {
"quotaResetDelay": "42s"
}
}
]
}
}表示されるべきもの:
- レスポンスボディに待ち時間が見つかる場合(例:
RetryInfo.retryDelayまたはquotaResetDelay)、プロキシは通常しばらく待ってから再試行します - 待ち時間がない場合、プロキシは組み込み戦略に従ってそのアカウントに「クールダウン期間」を追加し、再試行時に直接次のアカウントに切り替えます
第 2 ステップ:アカウントスケジューリング設定を確認
なぜか:スケジューリング設定はアカウントローテーション頻度と優先度に直接影響します
API Proxy ページに入り、スケジューリング戦略を確認:
| 設定項目 | 説明 | デフォルト/推奨 |
|---|---|---|
| Scheduling Mode | スケジューリングモード | Balance(デフォルト) |
| Preferred Account | 固定アカウントモード | 未選択(デフォルト) |
スケジューリングモード比較:
| モード | アカウント再利用戦略 | レート制限処理 | 適用シナリオ |
|---|---|---|---|
| CacheFirst | スティッキーセッションと 60 秒ウィンドウ再利用を有効 | 優先的に待機、Prompt Caching ヒット率を大幅に向上 | 会話型/高キャッシュヒット率が必要 |
| Balance | スティッキーセッションと 60 秒ウィンドウ再利用を有効 | 直ちに切り替えて代替アカウント、成功率とパフォーマンスを両立 | 一般的なシナリオ、デフォルト |
| PerformanceFirst | スティッキーセッションと 60 秒ウィンドウ再利用をスキップ、純粋なラウンドロビンモード | 直ちに切り替え、アカウント負荷が最も均等 | 高並列、ステートレスリクエスト |
キャッシュ優先 vs バランスモード
Prompt Caching を使用していてキャッシュヒット率を上げたい場合、CacheFirst を選択してください — レート制限時に優先的に待機してすぐにアカウントを切り替えません。成功率をキャッシュより重視する場合、Balance を選択してください — レート制限時にすぐにアカウントを切り替えます。
パフォーマンス優先モード
リクエストがステートレス(画像生成、独立クエリなど)の場合、PerformanceFirst を試してください。スティッキーセッションと 60 秒ウィンドウ再利用をスキップし、連続リクエストが異なるアカウントに落ちやすくします。
第 3 ステップ:アカウントローテーションが正常に動作しているか検証
なぜか:システムが自動的にアカウントを切り替えられることを確認
方法 1:レスポンスヘッダーを見る
curl または自分のクライアントでレスポンスヘッダーを印刷し、X-Account-Email が変化するか観察
方法 2:ログを確認
ログファイル(システムの場所に応じて)を開き、🔄 [Token Rotation] を検索:
🔄 [Token Rotation] Accounts: [
"account1@example.com(protected=[])",
"account2@example.com(protected=[])",
"account3@example.com(protected=[])"
]方法 3:Proxy Monitor を使用
Monitor ページでリクエストログを確認し、以下に注目:
- Account フィールドが異なるアカウント間で切り替わっているか
- Status が 429 のリクエストの後、異なるアカウントを使った成功したリクエストがあるか
表示されるべきもの:
- あるアカウントが 429 を返した後、後続リクエストが自動的に他のアカウントに切り替わる
- 複数のリクエストが同じアカウントを使ってすべて失敗している場合、スケジューリング設定の問題の可能性がある
第 4 ステップ:アカウント優先度を最適化
なぜか:システムが優先的に高クォータ/高ランクアカウントを使うようにし、429 確率を減らす
TokenManager では、アカウント選択前にアカウントプールを一度ソートします(🔄 [Token Rotation] Accounts: ... と印刷されます):
- サブスクリプションランク優先:ULTRA > PRO > FREE
- クォータパーセンテージ優先:同ランク内で、クォータが高いものが前
- ソートエントリー:このソートはプロキシ側で行われ、最終的にどのアカウントを使うかはプロキシ側ソート + 可用性判断が基準
インテリジェントソート原理(プロキシ側)
優先度は ULTRA > PRO > FREE;同一サブスクリプションランク内では remaining_quota(アカウント最大残りクォータパーセンテージ)降順。
操作:
- アカウントをドラッグして表示順序を調整(オプション)
- クォータをリフレッシュ(Accounts → すべてのクォータをリフレッシュ)
- アカウントのサブスクリプションランクとクォータを確認
罠の警告
❌ 間違い 1:429 を「モデルに容量がない」と誤解
現象:429 エラーを見ると、モデルに容量がないと思う
正しい理解:
- 429 はレート制限で、容量問題ではない
- アカウントを増やすと 429 確率を下げられる
- スケジューリングモードを調整すると切り替え速度を上げられる
❌ 間違い 2:クォータ保護閾値を高すぎる
現象:クォータは十分なのに、システムがずっとアカウントをスキップする
原因:Quota Protection は閾値より低いモデルをアカウントの protected_models に追加し、プロキシはスケジューリング時に「保護されたモデル」をスキップします。閾値が高すぎると、利用可能なアカウントが過度に除外される可能性があります。
修正:
- Settings → Quota Protection に戻り、監視モデルと閾値を調整
- どのモデルが保護されたのかをはっきりさせたい場合、アカウントデータで
protected_modelsを見る
❌ 間違い 3:固定アカウントモードでローテーションできない
現象:Preferred Account を設定したが、そのアカウントがレート制限されるとシステムが「詰まる」
原因:固定アカウントモードでは、システムは指定アカウントを優先的に使用し、アカウントが利用不可の場合のみラウンドロビンにダウングレードします。
修正:
- 固定アカウントが必要ない場合、
Preferred Accountをクリア - または固定アカウントのクォータが十分であることを確認し、レート制限を避ける
チェックポイント ✅
- [ ] クォータ不足とアップストリームレート制限を区別できる
- [ ] Proxy Monitor で 429 エラー詳細を確認する方法を知っている
- [ ] 3 つのスケジューリングモードの違いと適用シナリオを理解している
- [ ] アカウントローテーションが正常に動作しているか確認する方法を知っている
- [ ] アカウント優先度を最適化し、クォータ保護戦略を確認できる
よくある質問
Q1:複数のアカウントがあるのに、依然として 429 に遭遇するのはなぜ?
A:可能な原因:
- すべてのアカウントが同時にレート制限をトリガー(リクエスト頻度が高すぎる)
- 連続リクエストが「60 秒ウィンドウ再利用」で同じアカウントを繰り返し再利用し、単一アカウントをレート制限に打ち込みやすい
- クォータ保護が利用可能なアカウントを誤って除外
- アカウント総数があなたのリクエスト頻度を支えるのに不十分
解決:
- さらにアカウントを追加
PerformanceFirstモードを使用- Quota Protection があなたが使いたいモデルを
protected_modelsに追加していないか確認(必要なら監視モデルと閾値を調整) - リクエスト頻度を下げる
Q2:429 エラーは自動的に再試行されますか?
A:単一リクエスト内で自動再試行されます。再試行回数の上限は通常 3 回で、具体的な計算方法は min(3, アカウントプールサイズ) であり、少なくとも 1 回試行します。
再試行回数の例:
- アカウントプール 1 アカウント → 1 回試行(再試行なし)
- アカウントプール 2 アカウント → 2 回試行(再試行 1 回)
- アカウントプール 3 つ以上のアカウント → 3 回試行(再試行 2 回)
大まかな流れ:
- レート制限/過負荷情報を記録(
RateLimitTrackerに進入) - 待ち時間を解析できる場合(例:
RetryInfo.retryDelay/quotaResetDelay)、しばらく待ってから続行 - 再試行時に強制的にアカウントをローテーション(
attempt > 0の時force_rotate=true)、次の利用可能なアカウントでアップストリームリクエストを試行
すべての試行が失敗すると、プロキシはエラーをクライアントに返します。同時に、レスポンスヘッダー(例:X-Account-Email)または Proxy Monitor から実際に使用されたアカウントを確認できます。
Q3:あるアカウントがどのくらいレート制限されているか確認するには?
A:2 つの方法があります:
方法 1:ログを確認し、rate-limited を検索
🔒 [FIX #820] Preferred account xxx@gmail.com is rate-limited, falling back to round-robin方法 2:ログに残り待ち時間が表示されます
All accounts are currently limited. Please wait 30s.Q4:クォータ保護とレート制限は同じですか?
A:違います。
| 特性 | クォータ保護 | レート制限追跡 |
|---|---|---|
| トリガー条件 | モデルクォータが閾値より低い | 429 エラーを受信 |
| 適用範囲 | 特定のモデル | アカウント全体 |
| 持続時間 | クォータが回復するまで | アップストリームが決定(通常数秒から数分) |
| 動作 | そのモデルをスキップ | そのアカウントをスキップ |
Q5:どのようにしてすぐにアカウントを切り替えることを強制できますか?
A:「次回リクエストがアカウントを切り替えやすくする」という観点から着手できます:
- スケジューリング層:
PerformanceFirstに切り替え、スティッキーセッションと 60 秒ウィンドウ再利用をスキップ - 固定アカウント:
Preferred Accountが有効の場合、先にクリア。そうしないと優先的に固定アカウントを使う(レート制限/保護されるまで) - アカウントプール:アカウント数を増やし、単一アカウントがレート制限されたときに代替アカウントを見つけやすくする
単一リクエスト内では、プロキシ自体も再試行時に強制的にローテーションします(attempt > 0 は force_rotate=true をトリガー)、ただし再試行回数は上限制御を受けます。
レッスンまとめ
- 429 は Antigravity Tools では「アップストリームが一時的に利用不可」の信号のカテゴリであり、レート制限、クォータ枯渇、モデル容量不足などが原因の可能性がある
- プロキシはクールダウン時間を記録し、単一リクエストの再試行でアカウントローテーションを試みる(ただし再試行回数は限定的)
- スケジューリングモード、Quota Protection、アカウント数はすべてあなたが遭遇する 429 の確率と回復速度に影響する
- Proxy Monitor、レスポンスヘッダー
X-Account-Emailとログを使って問題を素早く特定できる
次のレッスン予告
次のレッスンでは 404/パス互換性:Base URL、/v1 プレフィックスと「重なりパス」クライアント を学びます
学べること:
- 最も一般的な接続エラー(404)がどのように発生するか
- 異なるクライアントの base_url 連結の違い
- 404 問題を素早く修正する方法
付録:ソースコード参照
クリックしてソースコードの場所を展開
更新時間:2026-01-23
| 機能 | ファイルパス | 行番号 |
|---|---|---|
| 429 再試行遅延解析(RetryInfo / quotaResetDelay) | src-tauri/src/proxy/upstream/retry.rs | 38-67 |
| Duration 解析ツール | src-tauri/src/proxy/upstream/retry.rs | 11-35 |
| スケジューリングモード列挙(CacheFirst/Balance/PerformanceFirst) | src-tauri/src/proxy/sticky_config.rs | 3-12 |
| レート制限原因解析とデフォルトクールダウン戦略 | src-tauri/src/proxy/rate_limit.rs | 5-258 |
| MAX_RETRY_ATTEMPTS 定数定義(OpenAI handler) | src-tauri/src/proxy/handlers/openai.rs | 14 |
| 再試行回数計算(max_attempts = min(MAX_RETRY_ATTEMPTS, pool_size)) | src-tauri/src/proxy/handlers/openai.rs | 830 |
| OpenAI handler:429/5xx 時にレート制限をマークし再試行/ローテーション | src-tauri/src/proxy/handlers/openai.rs | 349-389 |
| アカウントソート優先度(ULTRA > PRO > FREE + remaining_quota) | src-tauri/src/proxy/token_manager.rs | 504-538 |
| 60 秒ウィンドウ再利用 + レート制限/クォータ保護回避 | src-tauri/src/proxy/token_manager.rs | 624-739 |
| レート制限記録エントリー(mark_rate_limited) | src-tauri/src/proxy/token_manager.rs | 1089-1113 |
| 429 精密ロック/リアルタイムクォータリフレッシュ/ダウングレード戦略(mark_rate_limited_async) | src-tauri/src/proxy/token_manager.rs | 1258-1417 |
重要な定数:
MAX_RETRY_ATTEMPTS = 3:単一リクエスト内最大再試行回数(OpenAI/Gemini handler)60:60 秒ウィンドウ再利用(PerformanceFirst以外のモードでのみ有効)5:Token 取得タイムアウト時間(秒)300:Token 事前リフレッシュ閾値(秒、5 分)
重要な関数:
parse_retry_delay():429 エラーレスポンスから再試行遅延を抽出get_token_internal():アカウント選択とローテーションのコアロジックmark_rate_limited():アカウントをレート制限状態にマーク