◉CLAUDE LABEN
●2.1.302 — fork サブエージェントが claude -p・Agent SDK・デスクトップで既定オンになりました。無効化は CLAUDE_CODE_FORK_SUBAGENT=0(10/16)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り38日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.302 — fork サブエージェントが claude -p・Agent SDK・デスクトップで既定オンになりました。無効化は CLAUDE_CODE_FORK_SUBAGENT=0(10/16)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り38日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-10-22初級

上限に達したのに 400 が返ってきた — 自分で決めた利用上限・階層の月間上限・レート制限を見分ける

Claude API の「上限」系エラーは3種類あり、ステータスも待てば直るかどうかも違います。自分で設定した上限は400、階層の月間上限は429、通常のレート制限も429。見分けるコードと判断表をまとめました。

Claude API131エラー処理4296利用上限トラブルシューティング59

個人開発のアプリに付けている小さなバックエンドのジョブで、エラー処理を書き足していた夜、私自身は「上限に達したら 429 が返る」と思い込んだまま、429 だけを見張る分岐を組んでいました。月の利用上限を自分で決めておけば、超えたときは 429 で気づけるはずだ、と考えていたのです。

公式の rate limits のページを読み直して、その前提が半分しか合っていないことに気づきました。自分で設定した上限に達したときは、429 ではなく 400 が返ります。しかも、同じ 429 でも「待てば通るもの」と「月が替わるまで通らないもの」が混ざっています。

最初にお伝えしたいのは、上限まわりの失敗は3種類に分かれ、待つ価値があるのは、そのうち1種類だけだということです。見分け方と、その仕分けを書いたコードを書き残します。

「上限」と呼ばれるものは3つある

まず、名前が似ているものを並べて整理します。公式ドキュメントに書かれている内容を、私の言葉で表にしました。

種類ステータス見分ける手がかり待てば通るか
通常のレート制限429多くの場合 retry-after ヘッダが付く通る(秒数だけ待つ)
階層の月間上限(Start / Build / Scale)429error.details.error_code が enforced_spend_limit_reached。retry-after なし通らない(翌月 00:00 UTC まで、または階層の引き上げ)
自分で設定した利用上限400エラー種別は invalid_request_error。メッセージが You have reached your specified で始まる通らない(上限を上げるか外すまで)

階層ごとの月間上限は、公式の記載では Start が 500 ドル、Build が 1,000 ドル、Scale が 200,000 ドルです。カスタム契約には月間上限がなく、アカウント担当と取り決めます。

ここで厄介なのは、階層の月間上限と通常のレート制限が、どちらも rate_limit_error という同じ種別で返ってくる点です。種別の文字列だけを見て分岐すると、この2つは区別できません。

429 を見るだけでは足りない理由

SDK の自動リトライは、接続エラー・レート制限・5xx を、指数バックオフで既定2回まで再試行します。retry-after があればそれに従います。通常の 429 には、これがちょうど良い振る舞いです。

一方で、階層の月間上限の 429 には retry-after が付かず、公式にも「SDK の自動リトライを含め、アクセスが戻るまで失敗し続ける」と書かれています。待つほど無駄になる、ということです。

さらに、自分で決めた上限の 400 は、そもそもリトライの対象になりません。リクエストの書き方が悪いわけでもないのに invalid_request_error と出るので、プロンプトやパラメータを疑って時間を使いがちです。

補足: Claude Code 用のワークスペースに設けた上限だけは、超えると 400 ではなく、retry-after 付きの 429 になる場合があると公式に書かれています。Claude Code を同じ組織で動かしている方は、この例外も頭の片隅に置いておくと混乱しません。

見分けるコード(標準ライブラリだけ)

何を解決するかを先に言うと、このコードは「このエラーは待つ価値があるか」を1回の関数呼び出しで返します。上限に関係しないエラーなら None を返し、既存の処理に任せます。

"""Anthropic API の「上限」系エラーを仕分ける(標準ライブラリのみ)。"""
from __future__ import annotations
import json
from dataclasses import dataclass
 
@dataclass
class Verdict:
    kind: str    # tier_cap / own_limit / rate_limit
    retry: bool  # 待てば通る可能性があるか
    note: str
 
def classify(status: int, headers: dict[str, str], body: str) -> Verdict | None:
    """上限に関係しないエラーなら None を返す。"""
    try:
        err = json.loads(body).get("error", {})
    except (ValueError, AttributeError):
        return None  # HTML のエラーページなど、JSON でない応答
    message = err.get("message", "")
    code = (err.get("details") or {}).get("error_code", "")
    h = {k.lower(): v for k, v in headers.items()}
 
    if status == 429 and code == "enforced_spend_limit_reached":
        return Verdict("tier_cap", False, "階層の月間上限。翌月 00:00 UTC か階層の引き上げまで通らない")
    if status == 400 and message.startswith("You have reached your specified"):
        scope = "workspace" if "workspace" in message else "organization"
        return Verdict("own_limit", False, f"自分で設定した {scope} の上限。上限を上げるか外すまで通らない")
    if status == 429 and "retry-after" in h:
        return Verdict("rate_limit", True, f"{h['retry-after']} 秒待てば再試行できる")
    if status == 429:
        return Verdict("rate_limit", True, "retry-after なし。指数バックオフで様子を見る")
    return None

なぜこう書くかを3点だけ補足します。

  1. 429 より先に error_code を見ています。 種別(rate_limit_error)は通常のレート制限と同じなので、決め手にならないからです。
  2. 400 はメッセージの書き出しで判定しています。 invalid_request_error は本物のリクエスト不備にも使われます。公式が示している「You have reached your specified」という書き出しだけを手がかりにして、誤検知を避けました。
  3. JSON を読めなければ None で返します。 ゲートウェイが返す HTML のエラーページで、仕分け関数自体が落ちるのを防ぐためです。

手元で確かめた結果

ドキュメントに載っている応答の形を真似た疑似の応答を8通り作り、上のコードに通しました。実際の API を叩いたわけではなく、公式の記載どおりの本文を手で組んだものです。

入力判定待つか
429 + enforced_spend_limit_reachedtier_cap待たない
400 + 「specified API usage limits」own_limit(organization)待たない
400 + 「specified workspace API usage limits」own_limit(workspace)待たない
429 + retry-after: 12rate_limit12 秒待つ
429(ヘッダなし・通常の本文)rate_limitバックオフ
400(messages: field required)上限ではない(None)—
529上限ではない(None)—
502 + HTML 本文上限ではない(None)—

8件すべて期待どおりに仕分けられました。ただ、本物のメッセージの細部は変わる可能性があります。そのため私は、メッセージ文の一致は「補助の手がかり」にとどめ、error_code を主、ステータスを従として扱っております。

書いてみて気づいたのは、判定そのものよりも、「待たない」と決めたあとに誰へ知らせるかを先に決めておくほうが難しい、ということでした。止めるだけで通知がなければ、止まったことに数日気づかない可能性があるからです。

SDK の例外から使うとき

実際の呼び出しでは、SDK が投げる例外から status_code・ヘッダ・本文を取り出して渡します。

import anthropic
 
client = anthropic.Anthropic()  # ANTHROPIC_API_KEY は環境変数から読まれる
 
try:
    msg = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=256,
        messages=[{"role": "user", "content": "こんにちは"}],
    )
except anthropic.APIStatusError as e:
    v = classify(e.status_code, dict(e.response.headers), e.response.text)
    if v and not v.retry:
        # 待っても通らない。再試行せず、人に知らせて止める
        print(f"停止: {v.kind} / {v.note} / request_id={e.response.headers.get('request-id')}")
        raise SystemExit(1)
    raise  # それ以外は既存のエラー処理へ

request-id ヘッダは、サポートへ問い合わせるときに必要になります。止めるときに一緒に記録しておくと、後で自分が助かります。

SDK の自動リトライは、階層上限の 429 でも既定どおり2回走ります。止められないのは仕様ですが、2回で終わるので、無駄になるのは短い待ちだけです。待つ価値の有無は、再試行の前に決めます。 これが、このコードで私が引いた線です。

上限に当たったあとの動き方

見分けられたら、次の一手は種類ごとに決まっています。

  • 階層の月間上限(429): Console の Rate limits ページで階層を確認し、必要なら「Request tier increase」から引き上げを依頼します。階層を上げれば、アクセスが戻ると公式に書かれています。
  • 自分で決めた上限(400): Billing ページの Spend limits で、上限を上げるか外します。ワークスペース単位で決めている場合は、組織全体の上限とは別に当たることがあります。なお、既定のワークスペースには支出上限を設定できません。
  • 通常のレート制限(429): retry-after の秒数だけ待ちます。急に利用量を増やしたときに出る「加速制限」でも 429 が出るので、トラフィックは少しずつ増やすのが公式の推奨です。

通常のレート制限の余白をヘッダから測る方法は、別の記事に書きました。あわせてご覧ください。

次の一歩

まずは、自分の呼び出しコードで 429 を拾っている分岐を1つ探してみてください。そこに error_code の確認を1行足し、400 のメッセージも見張ってみてください。それだけで、月末に「なぜか通らない」と手が止まる夜は、はるかに減ります。

待てるエラーか、待てないエラーかは、再試行の前に決めます。 この一文だけは、疲れている日でも守るようにしています。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ API & SDK2026-10-16
Make から Claude API に 40 行流すと 14 行目で止まる — 429 を待ち時間の計算で避ける
表計算の行を1件ずつ Claude API に渡すノーコード自動化が、途中で 429 になる理由と直し方です。模擬バケットで7通りの間隔を比べ、Sleep の秒数を 60÷上限−応答時間 で決める式と、失敗行を落とさない設定を示します。
⬡ API & SDK2026-09-02
thinking ブロックを弾く 400 が出たとき、会話履歴のどこが書き換わっていたか
Claude Fable 5.1 から、thinking ブロックより前の system・tools・messages を書き換えたリクエストが 400 で弾かれるようになりました。自分のエージェントループが該当するかを1リクエストで確かめる手順と、system の組み立て直し・履歴の切り詰めを書き換えなしのやり方へ移す実装をまとめます。
⬡ API & SDK2026-04-26
Claude API の「Spanner temporarily unavailable」が返ってきたときの切り分けとリトライ設計
Claude API で「Spanner temporarily unavailable」が返ってきたときに、まず何を見るか。自分のコードか Anthropic 側かの切り分け、指数バックオフ+ジッターの実装、モデル降格、バッチ処理での割り切りまでを、運用で試した順に書き残します。