# Claude APIの500 api_error対処法：再試行後も失敗する場合の扱い

> 500 api_errorは、Anthropicのシステム内部で起きた予期しないエラーです。安全に繰り返せる呼び出しだけを有限回再試行し、失敗が続くなら送信を止めます。SDKの設定、取得できたリクエストID、同じ接続先での結果を残して、延期や問い合わせへ進んでください。

- URL: https://blog.laozhang.ai/ja/posts/claude-api-internal-server-error
- Published: 2026-05-02
- Updated: 2026-10-05
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ja/about)
- Topic: Claude と Anthropic
- Tags: Claude API, API Error 500, api_error, 内部サーバーエラー, 再試行, トラブルシューティング

---
Claude APIからHTTP `500`と`error.type: api_error`が返ったら、**リクエスト情報を保存し、安全に繰り返せる処理だけを、上限を決めて再試行します。** Anthropicの公式説明では、500はシステム内部で発生した予期しないエラーです。指数バックオフによる再試行が推奨され、続く場合はリクエストIDを添えてサポートへ問い合わせます。[APIエラーの公式説明](https://platform.claude.com/docs/ja/api/errors)

まずSDKが自動で再試行しているか確認してください。公式Python SDKは対象の一時的な失敗を既定で2回再試行します。アプリがさらに同じ呼び出しを繰り返すと、送信回数と待機時間が増えます。再試行を担当する箇所を一つに決め、終了後も500なら、利用者へ失敗を返すか、期限に余裕のあるジョブを後に回します。[Python SDKの再試行設定](https://platform.claude.com/docs/en/api/sdks/python)

500だけを理由に、APIキーの交換、再ログイン、プロンプトの全面的な変更へ進む必要はありません。何を受信したかを残したうえで、[Claude Status](https://status.claude.com/)のAPI関連情報を確認します。正常表示でも、個別のモデルや接続先が成功するとは限りません。

## 返された500と、応答が届かないエラーを区別する

HTTPステータス、エラーJSON、実際の接続先を確認します。次はAnthropic APIへ直接接続したときの500の形式を示す例です。リクエストIDは説明用で、実際の呼び出しを示していません。

```json
{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "Internal server error"
  },
  "request_id": "req_example"
}
```

`error.message`は表示用の文言なので、完全一致による判定よりHTTPステータスと型を使います。公式SDKでは、エラーJSONの代わりに型付き例外が発生します。Pythonでは`APIStatusError`の`status_code`と`response`から返されたHTTP応答を確認できます。[エラー形式と型付き例外](https://platform.claude.com/docs/ja/api/errors)、[Python SDKのエラー処理](https://platform.claude.com/docs/en/api/sdks/python)

| 確認できた情報 | 判断と次の操作 |
| --- | --- |
| Anthropic APIのHTTP `500`、`api_error` | 内部エラーとして記録し、安全な再試行を有限回行う |
| HTTP `529`、`overloaded_error` | 一時的な過負荷。[529の並列数・再試行制御](https://blog.laozhang.ai/ja/posts/claude-api-error-529-overloaded)へ進む |
| HTTP `429`、`rate_limit_error` | レート制限や一部の支出上限。エラー本文と制限情報を確認する |
| HTTP `504`、`timeout_error` | APIで処理中にタイムアウト。長時間の処理ならストリーミングなどを検討する |
| SDKの接続例外でHTTP応答が得られていない | 接続やクライアント側のタイムアウトとして調べる。500を受信したとは断定しない |
| 中継サービスのHTTP 500、HTMLのエラーページ | 中継サービスが何を返したか確認する。Anthropicの`api_error`と同一視しない |

この分類は[公式APIエラー一覧](https://platform.claude.com/docs/ja/api/errors)に基づきます。429のうち利用階層の月間支出上限によるものは、`retry-after`がなく、アクセスが再開するまで失敗し続けます。「500以上だから待つ」「エラーだからすべて再送する」と一括処理しないことが大切です。

`api_error`という文字列だけ、あるいは`no response from API`、`error sending prompt: internal error`という画面表示だけでは、実際にHTTP 500が返ったか分かりません。リクエストIDが見えなくても、SDKの公開方法や中継サービスのヘッダー処理によっては、HTTP応答自体は得られています。**IDの有無ではなく、応答や例外を確認してください。**

Claude Codeのターミナルで止まっている場合は、[500・529後に元のセッションと実行結果を確認する手順](https://blog.laozhang.ai/ja/posts/claude-code-500-529-rate-limit)が適切です。Webや連携アプリの表示しか分からない場合は、[利用画面と接続先から内部サーバーエラーを切り分ける方法](https://blog.laozhang.ai/ja/posts/claude-internal-server-error)を使えます。本記事では、APIを呼ぶアプリが返された500を扱う方法を進めます。

## Python SDKで再試行を任せ、最後の失敗を受け取る

単純な非ストリーミングの文章生成なら、SDKに再試行を任せ、アプリは成功と最終的な失敗を受け取る形にできます。以下は、500の失敗情報をJSONで出力し、終了コード`2`で処理を終える例です。ジョブ実行側はこの結果を使い、後で再実行するか、失敗として通知するかを決められます。

公式`anthropic`パッケージを利用し、APIキーを通常の方法で設定済みの環境を前提とします。`ANTHROPIC_MODEL`には、その環境で利用できる実際のモデルIDを設定してください。コードを`handle_500.py`として保存し、`python handle_500.py`で実行します。この例にツールの外部操作やストリームの再開機能はありません。

```python
import json
import os
import sys
from datetime import datetime, timezone

import anthropic


def status_record(exc: anthropic.APIStatusError) -> dict:
    body = exc.body if isinstance(exc.body, dict) else {}
    error = body.get("error")
    error = error if isinstance(error, dict) else {}
    request_id = (
        exc.response.headers.get("request-id")
        or body.get("request_id")
    )
    return {
        "http_status": exc.status_code,
        "error_type": error.get("type"),
        "request_id": request_id,
    }


def main() -> int:
    model = os.environ.get("ANTHROPIC_MODEL")
    if not model:
        raise SystemExit("ANTHROPIC_MODELに利用可能なモデルIDを設定してください")

    context = {
        "model": model,
        "endpoint": "/v1/messages",
        "sdk_max_retries": 2,
        "streaming": False,
    }
    with anthropic.Anthropic(max_retries=2, timeout=20.0) as client:
        try:
            message = client.messages.create(
                model=model,
                max_tokens=128,
                messages=[{"role": "user", "content": "短い挨拶を一文でお願いします。"}],
            )
        except anthropic.APITimeoutError:
            record = {"state": "client_timeout", **context}
            exit_code = 3
        except anthropic.APIConnectionError:
            record = {"state": "connection_error", **context}
            exit_code = 3
        except anthropic.APIStatusError as exc:
            state = "api_500" if exc.status_code == 500 else "other_http_error"
            record = {"state": state, **context, **status_record(exc)}
            exit_code = 2 if exc.status_code == 500 else 4
        else:
            for block in message.content:
                if block.type == "text":
                    print(block.text)
            return 0

    record["recorded_at_utc"] = datetime.now(timezone.utc).isoformat()
    print(json.dumps(record, ensure_ascii=False), file=sys.stderr)
    return exit_code


if __name__ == "__main__":
    sys.exit(main())
```

`max_retries=2`は、最初の送信に加えて最大2回の再試行です。成功や再試行を拒否する条件によって、早く終了することもあります。SDKは接続エラー、408、409、429、500以上を既定の対象としており、この例も500だけを再試行する設定ではありません。アプリ側は**SDKの呼び出しが終了した後の正確なHTTPステータス**で500を区別します。[SDKの仕様](https://platform.claude.com/docs/en/api/sdks/python)

`InternalServerError`というクラス名だけで「500」と決めないのも理由があります。公式SDKの文書には500以上のエラーとして記載され、2026年10月4日に確認したPython SDKの`main`ブランチでは529が別の`OverloadedError`へ分岐します。`main`の実装はインストール済みバージョンを保証しないため、コードは`APIStatusError.status_code == 500`を使っています。接続例外を含む基底の`APIError`すべてに`status_code`があるとは想定しません。[公式SDKのステータス別処理](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_client.py)、[例外の定義](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_exceptions.py)

このコードは、模擬クライアントによるオフライン確認で、成功、500、他のHTTPエラー、接続失敗、タイムアウトの分岐を確認しています。実APIでの復旧率や、待機時間は測定していません。

### timeoutを設定しても、全体が20秒で終わるとは限りません

上の`timeout=20.0`はクライアントのタイムアウト設定です。再試行とその前の待機を含め、プログラム全体を20秒以内に終える保証ではありません。タイムアウト自体もSDKの再試行対象です。[Python SDKのタイムアウト](https://platform.claude.com/docs/en/api/sdks/python)

また、現在の公式説明では`retry-after`があればその待機指示に従います。確認したPython SDKの`main`実装は、`retry-after-ms`、秒数、HTTP日時を解釈し、正の待機時間を使います。利用中の版での動作を確認し、長い待機指示が利用者の待てる時間を超えるなら、追加の即時送信をせず、後で処理する設計にしてください。[公式APIの再試行説明](https://platform.claude.com/docs/ja/api/errors)、[待機時間の実装](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_base_client.py)

対話画面の待機期限を厳密に守る必要があるなら、API呼び出しを別のジョブに分け、画面の待機終了とジョブの結果を個別に管理します。画面が待つのをやめても、サーバー側の処理が取り消されたとは限らないため、後から得られた結果を同じ業務ジョブに対応付けます。

## 再試行前に、重複して困る処理がないか確かめる

![500と他の失敗を分け、重複を確認して有限回で止める再試行の流れ](https://blog.laozhang.ai/posts/ja/claude-api-internal-server-error/img/recovery-loop.webp)

上の例は短いテキスト生成だけを行います。一方、実際のアプリが生成結果を使ってメールを送る、データを更新する、注文を確定するなら、APIの失敗と業務処理の失敗を分けて扱います。回答が得られなかったことだけでは、すでに実行した外部操作が取り消されたとは分かりません。

業務ジョブにはアプリ側の識別子を付け、送信済み・完了済み・結果不明の操作を保存します。再送する前に実際の記録を照合し、完了した操作を繰り返さないようにします。これはアプリ側の重複防止の設計です。任意の`Idempotency-Key`ヘッダーを付ければAnthropic Messages APIが必ず重複を防ぐ、という意味ではありません。

SDKの再試行が終わったあと、同じ関数をキューが即時再実行する構成にも注意してください。たとえば、アプリ側で最大3回呼び出し、各呼び出しがSDKで最大2回再試行するなら、送信は最大9回になります。これは「3回の初回送信＋各2回の再試行」の計算例で、実際の全経路の回数を示すものではありません。中継サービスの再試行はさらに別に確認する必要があります。

処理ごとに、再試行を誰が担当するか、いつ失敗を返すか、延期できる期限はいつかを決めます。SDKに任せる構成では、外側のループを増やす前に、SDKが待っている時間と最終結果を確認してください。

### HTTP 200の後で応答が途切れた場合

ストリーミングでは、HTTP 200を受信した後にエラーが起こることがあります。この場合、上の非ストリーミング用コードだけでは、応答が最後まで完了したかを判断できません。[公式のストリーミングエラー説明](https://platform.claude.com/docs/ja/api/errors)

`connection lost mid-response`や`The response above may be incomplete`に相当する失敗が出たら、受信した内容を未完成として保存し、ストリームの終了状態と実行済みの処理を確認します。再生成したテキストを途中の回答へそのまま追記したり、残ったツール呼び出しを無条件に再実行したりしないでください。どこから再開できるかはアプリの保存方法とSDKの実装に依存します。

## 500が続いたら、停止・延期・再開の結果を明確にする

同じモデルと接続先で、安全な再試行を終えても500なら、追加送信を止めます。まず利用者やジョブ実行側に「成功していない」という結果を返し、処理の重要度に応じて次の動きを選びます。

| 処理の状況 | 失敗後の扱い | 再開するときの確認 |
| --- | --- | --- |
| 利用者が画面で回答を待っている | 生成できなかったことを表示し、入力を保存する。成功として扱わない | 前の呼び出しが終了したか、保存された結果がないかを確認 |
| 後で実行できるバックグラウンド処理 | 同じ業務ジョブIDで延期し、次回の実行時刻と有効期限を残す | 期限内で未完了なら、少数のジョブから再開 |
| 外部操作がすでに進んでいる、または結果不明 | 自動再実行を止め、外部サービスの状態を照会する | 未完了と確認できた操作だけ実行 |
| 同じ呼び出しで500が繰り返し発生する | 失敗情報をまとめ、接続先の運営者へ問い合わせる | 正常な応答が完了したことを確認してから通常処理へ戻す |

公開障害情報がある場合は、その対象と更新内容を確認し、非緊急の仕事を待たせます。障害情報がなくても、回数を増やせば直るとは限りません。送信を一時停止する条件は、アプリの応答期限や失敗の広がりに合わせて決め、すべての連携に共通する「3回失敗したら別サービスへ移る」といった固定ルールにはしません。

復旧の確認は、元の接続先で応答が正常に完了したかを基準にします。ステータスページの色が変わっただけでは、自分の呼び出しの成功を確認できていません。モデルや接続先を一時的に変えて仕事を進めた場合も、「別の条件で成功した」という結果として残します。元の500の原因が判明したことにはなりません。

## 問い合わせに使えるリクエスト情報を残す

![Claude APIの500が続く場合に取得できた情報を整理する問い合わせ資料](https://blog.laozhang.ai/posts/ja/claude-api-internal-server-error/img/escalation-packet.webp)

直接Anthropic APIでは、応答ヘッダーの`request-id`とエラーJSONの`request_id`が同じリクエストを識別します。取得できる方を保存してください。成功時のPython SDKレスポンスにある`_request_id`と、失敗時の例外に付く情報は取得する箇所が異なります。上のコードは失敗したHTTP応答のヘッダーを優先し、なければJSONを確認します。[リクエストIDの公式説明](https://platform.claude.com/docs/ja/api/errors)

問い合わせでは、取得できた情報を次のようにまとめると、同じ呼び出しを追いやすくなります。

- 発生日時とタイムゾーン、HTTPステータス、`error.type`、機密情報を除いたエラーメッセージ。
- 各失敗で取得できたリクエストID。見つからない場合は、その旨と、取得できたHTTP情報。
- 実際の接続先、エンドポイント、モデルID、SDKの名前とバージョン、ストリーミングの有無。
- 初回送信と再試行の時刻・結果。SDK、アプリ、キュー、中継サービスそれぞれの再試行設定。
- 入力サイズ、メッセージ数、ツールの有無など、失敗したリクエストの特徴。
- 同じ条件で再発するか、変更した条件があるか、利用者や業務への影響。

上のコードが記録するリクエストIDは、SDKから最後に渡された失敗のものです。内部の再試行すべてのIDを取得するコードではありません。必要なら、利用中のSDKのログ機能や運用基盤で、安全に取得できる範囲の履歴を残します。分からない送信回数やIDを補って書く必要はありません。

原因を絞るときは、まず実際に失敗したモデル、接続先、リクエストの形式を残します。その後、機密情報を除いた最小限の有効な入力でも再発するかを確認できます。簡略化した入力が成功した場合は、元の入力と条件が違うため、元の障害が解消したとは判断しません。プロンプトを小さくすること自体を、500に対する保証された修復方法として扱わないでください。

APIキー、認証ヘッダー、顧客の本文、環境変数の一括出力は問い合わせ用の記録に含めません。エラーメッセージにも入力の一部が含まれていないか確認します。コード例はそのため、メッセージ全文ではなくステータス、型、IDを自動記録します。

中継サービスを使っているなら、まずその運営者へ問い合わせます。アプリが受け取った500と上流の応答を対応付け、上流のHTTPステータスやリクエストIDを確認してもらいます。直接Anthropic APIの500が続く場合は、[公式API文書の案内](https://platform.claude.com/docs/ja/api/errors)に従い、リクエストIDを添えてサポートへ連絡してください。

## よくある質問

### 500 api_errorが出たら、APIキーを交換すべきですか？

500だけを理由に交換する必要はありません。Anthropic APIの500は内部エラーで、APIキーの問題は401 `authentication_error`として別に説明されています。500の応答を保存し、有限回の再試行後も続くなら問い合わせへ進みます。[公式のエラー分類](https://platform.claude.com/docs/ja/api/errors)

### リクエストIDがない場合は、APIに接続できていませんか？

IDが見えないことだけでは断定できません。中継サービスがヘッダーを省略したり、SDKが別の箇所で公開したりする場合があります。HTTP応答が得られたかを確認し、得られていない接続例外と区別します。実際に取得できたステータス、本文、接続先を残してください。

### Claude Statusが正常なら、再試行を続けてよいですか？

正常表示だけでは継続の根拠になりません。個別のリクエストが成功するとは限らないため、アプリで決めた回数と待機の上限で止めます。失敗が続くなら、入力やジョブの状態を保存し、延期や問い合わせを選びます。

### Python SDKの再試行は、Claude Codeと同じ回数ですか？

別の仕組みです。公式Python SDKは対象の失敗を既定で2回再試行し、`max_retries`で調整できます。Claude Codeの動作はCLIの版や部分応答の状態にも依存するため、[Claude Codeでの再開手順](https://blog.laozhang.ai/ja/posts/claude-code-500-529-rate-limit)を参照してください。[Python SDKの仕様](https://platform.claude.com/docs/en/api/sdks/python)

## 参考資料

本文で参照している外部ページを、登場順に並べています。最終更新日：2026-10-05。

- [APIエラーの公式説明](https://platform.claude.com/docs/ja/api/errors) (platform.claude.com)
- [Python SDKの再試行設定](https://platform.claude.com/docs/en/api/sdks/python) (platform.claude.com)
- [Claude Status](https://status.claude.com/) (status.claude.com)
- [公式SDKのステータス別処理](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_client.py) (github.com)
- [例外の定義](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_exceptions.py) (github.com)
- [待機時間の実装](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_base_client.py) (github.com)
