0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude API の 429 / 529 エラーを正しくリトライする実装手順 — retry-after とレート制限ヘッダーの読み方、SDK の隠れ自動リトライなど3つのハマりどころ【2026】

0
Posted at

はじめに / 対象と前提

Claude API を業務で叩いていると、ある日突然 429 rate_limit_error529 overloaded_error が返ってくる。自分もバッチ処理を回している途中で 429 の嵐に遭い、「とりあえず sleep して再実行」で誤魔化していたら、今度はリトライが二重に走って余計に制限を食い潰す、という悪循環にハマった。

この記事は以下の読者向け。

  • Python で Claude API(Anthropic API)を呼んでいて、429 / 529 への対処を「なんとなく sleep」で済ませている人
  • SDK の自動リトライ仕様を把握しないままラッパーを自作しようとしている人

環境:Python 3.13 / anthropic SDK 1.x(2026年時点)

TL;DR

  • 429(レート制限)と 529(過負荷)は原因も対処も別物。429 は自分の使用量の問題、529 は Anthropic 側の混雑
  • Python SDK は デフォルトで 429 / 5xx を 2 回まで自動リトライしている(max_retries=2)。知らずに自前リトライを重ねると二重リトライになる
  • 429 のときは retry-after ヘッダーと anthropic-ratelimit-* ヘッダーを読めば「あと何秒待てばいいか」「どの制限に当たったか」が分かる

手順 / 動かし方

1. まず typed exception で 429 と 529 を区別する

SDK は HTTP ステータスごとに例外クラスを分けている。文字列マッチではなくクラスで捕まえるのが基本。

import anthropic

client = anthropic.Anthropic()

try:
    msg = client.messages.create(
        model="claude-opus-5",
        max_tokens=16000,
        messages=[{"role": "user", "content": "..."}],
    )
except anthropic.RateLimitError as e:      # 429 のみ
    print("rate limit:", e.message)
except anthropic.APIStatusError as e:      # その他の非2xx(529 含む)
    if e.type == "overloaded_error":       # ← .type で 529 を判別
        print("overloaded (529)")
    else:
        print(e.status_code, e.type)
except anthropic.APIConnectionError as e:  # レスポンス前のネットワーク断
    print("connection error")

ポイントは 2 つ。

  • RateLimitError が捕まえるのは 429 だけ。529 は 5xx 系なので InternalServerError(APIStatusError の子)側に落ちる
  • 例外オブジェクトの .type プロパティで API のエラー種別文字列("rate_limit_error" / "overloaded_error" など)が取れるので、ステータスコードより細かい分類ができる

2. レスポンスヘッダーで「どの制限に当たったか」を確認する

429 は RPM(リクエスト/分)・TPM(トークン/分)・TPD(トークン/日)のどれかを超えたときに返る。どれに当たったかはヘッダーで分かる。

resp = client.messages.with_raw_response.create(
    model="claude-opus-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "ping"}],
)
h = resp.headers
print(h.get("anthropic-ratelimit-requests-remaining"))  # RPM 残り
print(h.get("anthropic-ratelimit-tokens-remaining"))    # トークン残り
print(h.get("anthropic-ratelimit-requests-reset"))      # リセット時刻(RFC 3339)
message = resp.parse()  # 通常の Message オブジェクトに戻す

with_raw_response を挟むと生のレスポンスが取れる。正常時からこのヘッダーを監視しておけば、429 を食らう前に送信ペースを落とせる。

3. リトライは SDK に任せるのが第一選択

client = anthropic.Anthropic(max_retries=5)  # デフォルトは 2

SDK は 408 / 409 / 429 / 5xx と接続エラーを指数バックオフ付きで自動リトライする。429 に retry-after ヘッダーが付いていればそれも尊重する。大抵のケースはこの max_retries を増やすだけで足りる。自前で tenacity や while ループを書くのは、リトライ間の副作用(進捗保存・ログ・キュー返却)が必要になってからでいい。

ハマりどころ

ハマりどころ1:SDK の「隠れ自動リトライ」で二重リトライになる

自分が最初に踏んだのがこれ。tenacity で 3 回リトライを巻いたら、実際のリクエスト数は最大 3 × (1 + 2) = 9 回になっていた。SDK がデフォルトで 2 回リトライしている上に、外側のリトライが重なるからだ。

回避策:自前リトライを書くなら SDK 側を max_retries=0 にして役割を一本化する。逆に SDK に任せるなら外側には何も書かない。また、タイムアウトも各リトライに個別に適用されるので、体感の待ち時間は最悪 timeout × (max_retries + 1) まで伸びる。「処理が固まった」と思ったら実はリトライ中だった、はよくある。

ハマりどころ2:529 を 429 と同じ扱いにしてしまう

529 は overloaded_error、つまり Anthropic 側の過負荷で、自分の使用量とは無関係。429 対策として「送信ペースを半分にする」ロジックを 529 にも適用すると、意味なくスループットを落とすことになる。

回避策:529 は「時間を置いて指数バックオフで再試行」が正解。retry-after が付く保証もない。頻発するなら status.anthropic.com を確認しつつ、負荷の低いモデル(Haiku 系)への一時フォールバックやリクエストのキューイングを検討する。429 とは分岐を分けておくこと。

ハマりどころ3:TPM は「推定入力トークン」で先に消費される

TPM の消費はレスポンスが返ってから確定するのではなく、リクエスト受付時に推定入力トークン分が先に引かれる。だから長大なコンテキスト(大きなシステムプロンプトや履歴全体)を並列で投げると、リクエスト数は少ないのに TPM 側の 429 が出る。

回避策:並列実行するときは anthropic-ratelimit-tokens-remaining を見てセマフォを絞る。事前に client.messages.count_tokens() で入力サイズを見積もっておくと、1 リクエストで TPM の何割を食うのかが分かる。

まとめ

  • 429 と 529 は例外クラスと .type で明確に分岐する(RateLimitError は 429 専用)
  • リトライはまず SDK の max_retries に任せる。自前リトライを書くなら max_retries=0 で二重化を防ぐ
  • retry-afteranthropic-ratelimit-* ヘッダーを読めば、待ち時間と超過した制限の種類が分かる
  • TPM は推定入力トークンで先取り消費される。並列時は残量ヘッダーで送信を絞る

エラーを「とりあえず sleep」で潰すのをやめてヘッダーを読むようにしただけで、バッチの安定性は目に見えて変わった。同じところでハマっている人の参考になれば。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?