> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arouter.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# エラー処理

> ARouter のエラーレスポンス形式と、アプリケーションでの処理方法を理解します。

## エラー形式

すべてのエラーは一貫した JSON 形式に従います：

```json theme={null}
{
  "error": {
    "message": "人間が読めるエラーの説明",
    "type": "error_type"
  }
}
```

## エラータイプ

| HTTP ステータス | エラータイプ                                 | 説明                                |
| ---------- | -------------------------------------- | --------------------------------- |
| `400`      | `invalid_request_error`                | リクエストボディの形式が不正または必須フィールドが欠如       |
| `401`      | `authentication_error`                 | API key が欠如、無効、または期限切れ            |
| `402`      | `payment_required`                     | クレジット不足 — アカウントにチャージしてください        |
| `403`      | `permission_error` / `forbidden_error` | このキーは要求されたプロバイダーまたはリソースへのアクセス権がない |
| `413`      | `invalid_request_error`                | リクエストボディが大きすぎる（最大 10 MB）          |
| `429`      | `rate_limit_error`                     | レート制限超過（RPM または日次上限）              |
| `502`      | `server_error`                         | アップストリームプロバイダーへのリクエストが失敗          |
| `503`      | `server_error`                         | 要求されたモデルに利用可能なプロバイダーがない           |

## 一般的なエラーと解決策

### 401 — 無効な API Key

```json theme={null}
{
  "error": {
    "message": "invalid api key",
    "type": "authentication_error"
  }
}
```

**解決策：** API key が正しく、失効していないことを確認してください。

### 403 — プロバイダーが許可されていない

```json theme={null}
{
  "error": {
    "message": "provider 'anthropic' is not allowed for this API key",
    "type": "forbidden_error"
  }
}
```

**解決策：** お使いの API key には `allowed_providers` の制限があります。別のキーを使用するか、管理 API で許可されたプロバイダーを更新してください。

### 429 — レート制限

```json theme={null}
{
  "error": {
    "message": "rate limit exceeded",
    "type": "rate_limit_error"
  }
}
```

**解決策：** 指数バックオフを実装してください。キーのレート制限の引き上げを検討してください。

### 502 — アップストリームエラー

```json theme={null}
{
  "error": {
    "message": "upstream request failed",
    "type": "server_error"
  }
}
```

**解決策：** LLM プロバイダーがエラーを返したか、アクセスできません。ARouter は自動的にキーのフェイルオーバーを処理しますが、プロバイダー自体に問題が発生している可能性があります。リトライするか、別のプロバイダーに切り替えてください。

## コードでのエラー処理

<Tabs>
  <Tab title="Python (OpenAI)">
    ```python theme={null}
    from openai import OpenAI, APIStatusError, APIConnectionError

    client = OpenAI(
        base_url="https://api.arouter.ai/v1",
        api_key="lr_live_xxxx",
    )

    try:
        response = client.chat.completions.create(
            model="openai/gpt-5.4",
            messages=[{"role": "user", "content": "Hello!"}],
        )
    except APIStatusError as e:
        if e.status_code == 401:
            print("Invalid API key")
        elif e.status_code == 402:
            print("Insufficient credits — top up your account")
        elif e.status_code == 429:
            print("Rate limited, backing off...")
        elif e.status_code in (502, 503):
            print("Provider error, retrying...")
        else:
            print(f"API error {e.status_code}: {e.message}")
    except APIConnectionError:
        print("Network error — check your connection")
    ```
  </Tab>

  <Tab title="Node.js (OpenAI)">
    ```typescript theme={null}
    import OpenAI from "openai";

    const client = new OpenAI({
      baseURL: "https://api.arouter.ai/v1",
      apiKey: "lr_live_xxxx",
    });

    try {
      const response = await client.chat.completions.create({
        model: "openai/gpt-5.4",
        messages: [{ role: "user", content: "Hello!" }],
      });
    } catch (error) {
      if (error instanceof OpenAI.APIError) {
        switch (error.status) {
          case 401: console.error("Invalid API key"); break;
          case 402: console.error("Insufficient credits"); break;
          case 429: console.error("Rate limited"); break;
          case 502:
          case 503: console.error("Provider error"); break;
          default:  console.error(`Error ${error.status}: ${error.message}`);
        }
      }
    }
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    resp, err := client.ChatCompletion(ctx, req)
    if err != nil {
        var apiErr *arouter.APIError
        if errors.As(err, &apiErr) {
            switch apiErr.StatusCode {
            case 401:
                log.Fatal("Invalid API key")
            case 429:
                log.Println("Rate limited, backing off...")
                time.Sleep(time.Second)
            case 502:
                log.Println("Provider error, retrying...")
            }
        } else {
            log.Fatal("Network error:", err)
        }
    }
    ```
  </Tab>
</Tabs>

## リトライ戦略

本番アプリケーションでは以下を推奨します：

1. **429 と 502 には指数バックオフでリトライ**
2. **400、401、403 はリトライしない** — これらは永続的なエラー
3. **最大リトライ回数を設定**（例: 3 回）
4. **マルチモデルルーティングを検討** — あるモデルがリクエストに応えられない場合、`models` と `route` で順序付きの候補リストを送信

```python theme={null}
import time
from openai import OpenAI, APIStatusError

def call_with_retry(client, request, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.chat.completions.create(**request)
        except APIStatusError as e:
            if e.status_code in (429, 502, 503) and attempt < max_retries - 1:
                time.sleep(2 ** attempt)
                continue
            raise
```

## ストリーミング中のエラー処理

ストリーミング（`stream: true`）を使用する場合、エラーの動作は発生するタイミングによって異なります：

* **Token が送信される前** — ARouter は非 200 ステータスコードを持つ標準 HTTP エラーレスポンスを返します。非ストリーミングエラーと同様に処理します。
* **Token が送信された後** — HTTP ステータスはすでに 200 OK です。エラーはストリームボディ内の SSE イベントとして配信されます。

ストリーム途中のエラーは次のようになります：

```json theme={null}
{
  "id": "chatcmpl-xxx",
  "object": "chat.completion.chunk",
  "error": {
    "code": "server_error",
    "message": "Provider disconnected unexpectedly"
  },
  "choices": [
    { "index": 0, "delta": { "content": "" }, "finish_reason": "error" }
  ]
}
```

各チャンクの `finish_reason` を確認してください。`"error"` の場合、ストリームが異常終了したことを意味します。

```typescript theme={null}
for await (const chunk of stream) {
  // Check for mid-stream error
  if ("error" in chunk) {
    console.error(`Stream error: ${(chunk as any).error.message}`);
    break;
  }
  if (chunk.choices[0]?.finish_reason === "error") {
    console.error("Stream terminated due to an error");
    break;
  }
  const content = chunk.choices[0]?.delta?.content;
  if (content) process.stdout.write(content);
}
```

完全なストリーミングエラー処理の例については、[ストリーミングガイド](/jp/guides/streaming)を参照してください。
