> ## Documentation Index
> Fetch the complete documentation index at: https://adcp-docs-ja.pier1.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# トランスポートエラーマッピング

> AdCP の構造化エラーが MCP と A2A トランスポートを通じて伝達される方法: 抽出パス、JSON-RPC コード、リカバリー動作、クライアント実装要件。

AdCP エラーは**アプリケーション層**のエラーです。トランスポートエラーチャネルではなく、ツール/タスクレスポンスに属します。このページでは [`error.json`](https://adcontextprotocol.org/schemas/latest/core/error.json) スキーマが MCP と A2A レスポンスエンベロープにどのようにマッピングされるかを定義します。

エラースキーマ自体、標準コード、リカバリー戦略については[エラーハンドリング](/docs/building/by-layer/L3/error-handling)を参照。

## 層の分離

| 層        | 例                                                   | チャネル                            |
| -------- | --------------------------------------------------- | ------------------------------- |
| トランスポート  | 接続拒否、不正な JSON-RPC、内部クラッシュ                           | JSON-RPC `error` / A2A プロトコルエラー |
| アプリケーション | `RATE_LIMITED`、`BUDGET_TOO_LOW`、`CREATIVE_REJECTED` | ツール/タスクレスポンスボディ                 |

トランスポートエラーはプロトコルライブラリが処理します。アプリケーションエラーはビジネスロジックが処理します。混在させると、AdCP エラーを有用にする構造化リカバリーデータが失われる。

## MCP バインディング

### ツールレベルエラー

すべての AdCP エラーコードの標準パス。ツールが実行し、リクエストを理解して、構造化エラーを返します。

**現在の実用的なパス:** ほとんどの MCP ホスト（Claude Desktop、Cursor、Windsurf）はエラーレスポンスの `content` テキストを読み取り、`structuredContent` を LLM やプログラム的なコンシューマーに公開しません。`structuredContent` の採用が広まるまで、テキストフォールバックパスがほとんどのエラーが抽出される方法です。サーバーは両方のパスをサポートすべきだ:

```json theme={null}
{
  "content": [{"type": "text", "text": "{\"adcp_error\":{\"code\":\"RATE_LIMITED\",\"message\":\"Request rate exceeded\",\"retry_after\":5,\"recovery\":\"transient\"}}"}],
  "isError": true,
  "structuredContent": {
    "adcp_error": {
      "code": "RATE_LIMITED",
      "message": "Request rate exceeded",
      "retry_after": 5,
      "recovery": "transient"
    }
  }
}
```

**`content` テキスト**は AdCP エラーをテキストベース抽出用の JSON 文字列として含みます。**`structuredContent.adcp_error`** はプログラム的クライアントが同じエラーをサポートする場合に含みます。人間が読めるテキストを含めるサーバーは2番目のコンテンツアイテムとして追加すべきで、簡潔に保つ（1文）:

```json theme={null}
{
  "content": [
    {"type": "text", "text": "{\"adcp_error\":{\"code\":\"RATE_LIMITED\",\"message\":\"Request rate exceeded\",\"retry_after\":5,\"recovery\":\"transient\"}}"},
    {"type": "text", "text": "Rate limited — retry in 5s."}
  ],
  "isError": true,
  "structuredContent": {
    "adcp_error": {
      "code": "RATE_LIMITED",
      "message": "Request rate exceeded",
      "retry_after": 5,
      "recovery": "transient"
    }
  }
}
```

**`structuredContent` 存在時の簡潔なテキスト。** `structuredContent` が完全なエラーを含む場合、人間が読めるテキストコンテンツアイテムは1つの簡潔な文（例: "Rate limited — retry in 5s."）にすべきです。エラーの詳細はすでに `structuredContent` と JSON テキストフォールバックにある。散文でエラー全体を繰り返すと、特にリトライ中に蓄積する一時的なエラーの場合、LLM コンテキストトークンが無駄になります。

**`adcp_error` キー**: 名前空間化により `structuredContent` にも現れる可能性のある成功データ（例: `products`）との衝突を避ける。単一のキーにより検出が簡単になります。

**`structuredContent`** には MCP 2025-03-26 以降が必要です。古い MCP バージョンのサーバーは `structuredContent` を省略する — `content[0].text` の JSON 文字列で十分です。クライアントはテキストフォールバックパスを通じてこれを解析する（[クライアント検出順序](#client-detection-order)を参照）。

### トランスポートレベルエラー

ツールディスパッチの前にインフラ（API ゲートウェイ、レートリミットミドルウェア）がリクエストを拒否した場合、ツールは実行されない。`data` に AdCP エラーを含む予約済み JSON-RPC エラーコードを使用します:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": "req-123",
  "error": {
    "code": -32029,
    "message": "Rate limit exceeded",
    "data": {
      "adcp_error": {
        "code": "RATE_LIMITED",
        "retry_after": 5,
        "recovery": "transient"
      }
    }
  }
}
```

### 予約済み JSON-RPC コード

| コード      | AdCP エラーコード           | タイミング                     |
| -------- | --------------------- | ------------------------- |
| `-32029` | `RATE_LIMITED`        | ツールディスパッチ前のインフラレートリミット    |
| `-32028` | `AUTH_REQUIRED`       | ツールディスパッチ前にミドルウェアが認証を拒否   |
| `-32027` | `SERVICE_UNAVAILABLE` | インフラヘルスチェック失敗、アップストリームダウン |

これらのコードは JSON-RPC サーバー定義範囲（`-32000` から `-32099`）にある。他のすべての AdCP エラーコードはツールレベルパスのみを使用します。

<Note>
  **MCP サーバー SDK の注意:** ツールハンドラー内から `McpError` をスローすると JSON-RPC エラーレスポンスが生成される — SDK はそれを `isError: true` ツール結果に変換**しない**。つまり `-32029` はミドルウェアからスローされても、ツールハンドラーからスローされても同じように機能します。しかしアプリケーション層エラー（ツールがリクエストを理解して構造化された失敗を返す場合）は、JSON-RPC エラーコードではなく上記の `isError: true` ツールレベルパスを使うべきです。`-32029`/`-32028`/`-32027` はツールディスパッチ前にリクエストを拒否するインフラのために予約します。
</Note>

### MCP サーバー実装

```javascript theme={null}
function adcpErrorResponse(error) {
  const adcpError = {
    code: error.code,
    message: error.message,
    recovery: error.recovery,
    ...(error.retry_after != null && { retry_after: error.retry_after }),
    ...(error.field != null && { field: error.field }),
    ...(error.suggestion != null && { suggestion: error.suggestion }),
    ...(error.details != null && { details: error.details }),
  };
  return {
    content: [{ type: "text", text: JSON.stringify({ adcp_error: adcpError }) }],
    isError: true,
    structuredContent: { adcp_error: adcpError },
  };
}

server.tool(
  "get_products",
  "Search product catalog",
  { query: z.string() },
  async ({ query }) => {
    try {
      const products = await searchProducts(query);
      return {
        content: [{ type: "text", text: `Found ${products.length} products` }],
        structuredContent: { products },
      };
    } catch (err) {
      if (err.code && err.recovery) {
        return adcpErrorResponse(err);
      }
      throw err;
    }
  }
);
```

## A2A バインディング

### 失敗したタスク

`DataPart` の AdCP エラーと人間/LLM 用の `TextPart` を含む `status: "failed"` を使用します:

```json theme={null}
{
  "id": "task_456",
  "status": {
    "state": "failed",
    "timestamp": "2025-01-22T10:30:00Z"
  },
  "artifacts": [{
    "artifactId": "error-result",
    "parts": [
      {
        "kind": "text",
        "text": "Rate limit exceeded. Retry in 5 seconds."
      },
      {
        "kind": "data",
        "data": {
          "adcp_error": {
            "code": "RATE_LIMITED",
            "message": "Request rate exceeded",
            "retry_after": 5,
            "recovery": "transient"
          }
        }
      }
    ]
  }]
}
```

これは[A2A レスポンスフォーマット](/docs/building/by-layer/L0/a2a-response-format)の規則に従う: 最終状態はデータに `.artifacts` を使用します。

**「ラッパーなし」ルールとの関係。** `adcp_error` キーは失敗したタスクの意図的な例外です。成功レスポンスの `DataPart` がタスク固有のデータ（例: `products`）を含むのとは異なり、失敗したタスクの `DataPart` はエラーのみを含みます。このキーは型の識別子として機能し、クライアントがステータスだけに頼ることなくエラーと成功ペイロードを区別できるようにします。

### エラー MIME タイプ（オプション）

A2A エージェントはエラー `DataPart` の `metadata.mimeType` を設定してもよい:

```json theme={null}
{
  "kind": "data",
  "data": { "adcp_error": { "code": "RATE_LIMITED", "recovery": "transient" } },
  "metadata": { "mimeType": "application/vnd.adcp.error+json" }
}
```

クライアントは MIME タイプを必要としてはなりません。`adcp_error` キーが権威あるシグナルです。

## エンベロープ vs. ペイロードエラー

AdCP はエラーを 2 つの異なる場所で公開します。本ページは**トランスポートエンベロープ**（`adcp_error`）を扱います。**ペイロードエラー配列**（`errors[]`）は [Error Handling — Envelope vs. payload errors](/docs/building/by-layer/L3/error-handling#envelope-vs-payload-errors-the-two-layer-model) で扱います。

| 層                       | キー                                                                         | いつ設定するか                                     | 読み手                            |
| ----------------------- | -------------------------------------------------------------------------- | ------------------------------------------- | ------------------------------ |
| **トランスポートエンベロープ**（本ページ） | `adcp_error`（MCP `structuredContent`、A2A `DataPart`、JSON-RPC `error.data`） | タスクが失敗した。トランスポートに型付き・抽出可能なエラーシグナルが必要        | MCP ホスト、A2A クライアント、`@adcp/sdk` |
| **タスクペイロード**            | `payload.errors[]`（またはトップレベル `errors[]`）                                   | タスクが実行された。ペイロードが 1 つ以上の問題（致命的または非致命的な警告）を報告 | ビジネスロジックのコンシューマー               |

致命的なタスク失敗は**両方**の層を設定すべきです（SHOULD） — 正規の `protocol-envelope.json` の例と、規範的な SHOULD については `error-handling.mdx` リファレンスを参照してください。

## クライアント検出順序

クライアントはこの順序で AdCP エラーを確認しなければなりません:

1. **`structuredContent.adcp_error`**（`isError: true` 付き）— MCP ツールレベルエラー
2. **`artifacts[].parts[].data.adcp_error`** — A2A タスクレベルエラー（アーティファクト）
3. **`status.message.parts[].data.adcp_error`** — A2A タスクレベルエラー（ステータスメッセージ）
4. **`error.data.adcp_error`** — JSON-RPC トランスポートレベルエラー
5. **`adcp_error` キーを含む JSON パースされた `content[].text`** — 古い MCP サーバー用のテキストフォールバック（`isError` レスポンスのみ）
6. **`payload.errors[0]`**（またはトップレベル `errors[0]`）— ペイロード層フォールバック。トランスポートエンベロープが `adcp_error` を表面化しないがペイロードが `errors[]` 配列を運ぶ場合に使用。ペイロード層のみが設定される非致命的なケース（例: 警告を報告する `input-required` タスク）ではペイロードからの読み取りは正当だが、ペイロード経由でのみエラーを表面化する致命的なタスクはエージェント側のコンフォーマンスギャップです。
7. **構造化エラーが見つからない** — 汎用エラー処理にフォールバック

クライアントは抽出されたエラーに `string` 型の `code` フィールドがあることを検証しなければなりません。検証が失敗した場合は、構造化エラーが見つからないとして扱います。

### Storyboard `check: error_code` 契約

Storyboard バリデーターは、エラーがどちらの層にも表面化し得るため、パス固有のアサーションではなく `check: error_code` を使用します。ランナー契約:

* `check: error_code` は、上記の[クライアント検出順序](#client-detection-order)を実行してエラーコードを解決します — 優先順位: `adcp_error.code`（トランスポート）→ `errors[0].code`（ペイロード）。
* どちらの層も `code` を運ばない場合、検証は `error_code_not_resolvable` で失敗します。
* Storyboard 作成者はアサーションを特定のパス（例: `check: field_present, path: "errors"`）にピン留めすべきではありません（SHOULD NOT） — それはテストを 1 つの層に結合し、もう一方の層にエラーを表面化するエージェントに対して失敗します。[Storyboard authoring — Asserting on errors](/docs/contributing/storyboard-authoring#asserting-on-errors) を参照してください。

**抽出 vs アクション。** 上記の検出順序は*抽出*層だ — フィールド値をそのまま保持した生の `adcp_error` オブジェクトを返す（範囲外の `retry_after` を含む）。クランプ、リトライロジック、その他の動作要件は*アクション*層で適用されます（[リカバリー動作](#recovery-behavior)を参照）。

実際には、実装はまずトランスポートタイプで分岐し、関連するパスのみを確認します:

<CodeGroup>
  ```javascript MCP Client theme={null}
  function extractAdcpErrorFromMcp(response) {
    if (!response.isError) return null;

    // 1. structuredContent (preferred)
    if (response.structuredContent?.adcp_error) {
      return validate(response.structuredContent.adcp_error);
    }

    // 2. Text fallback
    if (response.content) {
      for (const item of response.content) {
        if (item.type === 'text' && item.text) {
          try {
            const parsed = JSON.parse(item.text);
            if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)
                && parsed.adcp_error) {
              return validate(parsed.adcp_error);
            }
          } catch { /* not JSON */ }
        }
      }
    }

    return null;
  }

  // Reject malformed or oversized payloads
  function validate(error) {
    if (!error || typeof error !== 'object' || Array.isArray(error)) return null;
    if (typeof error.code !== 'string') return null;
    if (error.code.length === 0 || error.code.length > 64) return null;
    if (JSON.stringify(error).length > 4096) return null;
    return error;
  }

  // For JSON-RPC errors (caught as McpError)
  function extractAdcpErrorFromMcpError(error) {
    return validate(error.data?.adcp_error);
  }
  ```

  ```javascript A2A Client theme={null}
  function extractAdcpErrorFromA2a(task) {
    // 1. Artifacts (preferred — final state data)
    if (task.artifacts) {
      for (const artifact of task.artifacts) {
        const dataParts = (artifact.parts || []).filter(p => p.kind === 'data');
        for (const part of dataParts) {
          if (part.data?.adcp_error) {
            return validate(part.data.adcp_error);
          }
        }
      }
    }

    // 2. status.message.parts (some A2A implementations)
    const parts = task.status?.message?.parts;
    if (Array.isArray(parts)) {
      for (const part of parts) {
        if (part.kind === 'data' && part.data?.adcp_error) {
          return validate(part.data.adcp_error);
        }
      }
    }

    return null;
  }
  ```
</CodeGroup>

## リカバリー動作

抽出後、`recovery` フィールドに基づいてリカバリーを適用する:

| リカバリー         | クライアント動作                                                                                 |
| ------------- | ---------------------------------------------------------------------------------------- |
| `transient`   | `retry_after` 秒後にリトライします。`retry_after` が欠如または非有限の場合は、クライアントの設定された初期遅延から始まる指数バックオフを使用します。 |
| `correctable` | `suggestion` と `field` を呼び出し元に示し、自動リトライはしない                                              |
| `terminal`    | 人間のオペレーターにエラーを示し、リトライしない                                                                 |

**`retry_after` の境界:** セラーは 1 から 3600 秒の `retry_after` 値を返さなければなりません。クライアントはこの範囲外の値をクランプしなければなりません: 1 未満は 1 に、3600 超は 3600 になります。非有限値（`NaN`、`Infinity`）は欠如として扱わなければなりません。これにより、設定が間違ったサーバーからの積極的なリトライループと病的に長いストールの両方を防ぐ。

**リトライ上限:** バイヤーエージェントはオペレーションごとに最大リトライ回数（例: 3 回）と最大累積リトライ時間（例: 300 秒）を強制すべきです。リトライバジェットを超えて持続する一時的エラーはターミナルとしてエスカレーションすべきです。上限なしでは、すべてのリクエストで `retry_after: 3600` を返す悪意のある、または設定が間違ったセラーがエージェントを無期限に停滞させる可能性があります。

**`recovery` が欠如している場合:** 標準エラーコードテーブルを使用してコードベースの分類にフォールバックします。これにより、[レベル 1](/docs/building/by-layer/L3/error-handling#compliance-levels) サーバー（`code` と `message` のみを返す）でも、対応するクライアントから正しいリカバリー動作を得られます。コードも不明の場合は、`terminal` として扱います。

未知の `recovery` 値（前方互換性）については、`terminal` として扱います。

```javascript theme={null}
// Standard code → recovery mapping for when recovery field is absent
const CODE_RECOVERY = {
  RATE_LIMITED: 'transient',
  SERVICE_UNAVAILABLE: 'transient',
  CONFLICT: 'transient',
  INVALID_REQUEST: 'correctable',
  AUTH_REQUIRED: 'correctable',
  POLICY_VIOLATION: 'correctable',
  PRODUCT_NOT_FOUND: 'correctable',
  PRODUCT_UNAVAILABLE: 'correctable',
  PROPOSAL_EXPIRED: 'correctable',
  BUDGET_TOO_LOW: 'correctable',
  CREATIVE_REJECTED: 'correctable',
  UNSUPPORTED_FEATURE: 'correctable',
  AUDIENCE_TOO_SMALL: 'correctable',
  ACCOUNT_SETUP_REQUIRED: 'correctable',
  ACCOUNT_AMBIGUOUS: 'correctable',
  COMPLIANCE_UNSATISFIED: 'correctable',
  ACCOUNT_NOT_FOUND: 'terminal',
  ACCOUNT_PAYMENT_REQUIRED: 'terminal',
  ACCOUNT_SUSPENDED: 'terminal',
  BUDGET_EXHAUSTED: 'terminal',
};

function getRecovery(adcpError) {
  if (adcpError.recovery) return adcpError.recovery;
  return CODE_RECOVERY[adcpError.code] || 'terminal';
}

function handleAdcpError(adcpError) {
  switch (getRecovery(adcpError)) {
    case 'transient':
      const raw = adcpError.retry_after;
      const delay = Number.isFinite(raw) ? Math.max(1, Math.min(3600, raw)) : null;
      return { action: 'retry', delaySeconds: delay };

    case 'correctable':
      return {
        action: 'fix_request',
        field: adcpError.field,
        suggestion: adcpError.suggestion,
      };

    case 'terminal':
      return { action: 'escalate', message: adcpError.message };

    default:
      // Unknown recovery value: treat as terminal
      return { action: 'escalate', message: adcpError.message };
  }
}
```

## 推奨 `details` 形式

`details` フィールドはオープンオブジェクトです。相互運用性の発散を防ぐため、セラーは一般的なエラーコードの `details` を設定する際にこれらの標準キーを使用すべきだ:

### `RATE_LIMITED`

```json theme={null}
{
  "code": "RATE_LIMITED",
  "retry_after": 5,
  "recovery": "transient",
  "details": {
    "limit": 100,
    "remaining": 0,
    "window_seconds": 60,
    "scope": "account"
  }
}
```

| キー               | 型      | 説明                                        |
| ---------------- | ------ | ----------------------------------------- |
| `limit`          | number | ウィンドウ内で許可される最大リクエスト数                      |
| `remaining`      | number | 現在のウィンドウで残っているリクエスト数                      |
| `window_seconds` | number | レートリミットウィンドウの長さ                           |
| `scope`          | string | 制限が適用される対象: `account`、`tool`、または `global` |

### `BUDGET_TOO_LOW`

```json theme={null}
{
  "code": "BUDGET_TOO_LOW",
  "recovery": "correctable",
  "details": {
    "minimum_budget": 500,
    "currency": "USD"
  }
}
```

| キー               | 型      | 説明              |
| ---------------- | ------ | --------------- |
| `minimum_budget` | number | このプロダクトのセラー最小予算 |
| `currency`       | string | ISO 4217 通貨コード  |

### `AUDIENCE_TOO_SMALL`

```json theme={null}
{
  "code": "AUDIENCE_TOO_SMALL",
  "recovery": "correctable",
  "details": {
    "minimum_size": 10000,
    "current_size": 2500
  }
}
```

| キー             | 型      | 説明              |
| -------------- | ------ | --------------- |
| `minimum_size` | number | 必要な最小オーディエンスサイズ |
| `current_size` | number | 現在のオーディエンスサイズ   |

### `ACCOUNT_SETUP_REQUIRED`

```json theme={null}
{
  "code": "ACCOUNT_SETUP_REQUIRED",
  "recovery": "correctable",
  "details": {
    "setup_url": "https://seller.example.com/setup/acct_123",
    "setup_steps": ["Accept terms of service", "Add payment method"]
  }
}
```

| キー            | 型         | 説明                    |
| ------------- | --------- | --------------------- |
| `setup_url`   | string    | アカウントセットアップを完了できる URL |
| `setup_steps` | string\[] | アカウントが準備できるまでの残りのステップ |

### `CREATIVE_REJECTED`

```json theme={null}
{
  "code": "CREATIVE_REJECTED",
  "recovery": "correctable",
  "suggestion": "Revise creative to comply with alcohol advertising policy",
  "details": {
    "policy_id": "alcohol-advertising-v2",
    "policy_url": "https://seller.example.com/policies/alcohol-advertising",
    "reasons": ["Contains health claims not permitted for alcohol products"]
  }
}
```

| キー           | 型         | 説明                  |
| ------------ | --------- | ------------------- |
| `policy_id`  | string    | 違反したポリシーの識別子        |
| `policy_url` | string    | 完全なポリシーを確認できる URL   |
| `reasons`    | string\[] | クリエイティブが拒否された具体的な理由 |

### `POLICY_VIOLATION`

```json theme={null}
{
  "code": "POLICY_VIOLATION",
  "recovery": "correctable",
  "details": {
    "policy_id": "targeting-restrictions-v3",
    "policy_url": "https://seller.example.com/policies/targeting",
    "violated_rules": ["No age-based targeting for financial products"]
  }
}
```

| キー               | 型         | 説明                |
| ---------------- | --------- | ----------------- |
| `policy_id`      | string    | 違反したポリシーの識別子      |
| `policy_url`     | string    | 完全なポリシーを確認できる URL |
| `violated_rules` | string\[] | 違反した具体的なルール       |

### `CONFLICT`

```json theme={null}
{
  "code": "CONFLICT",
  "recovery": "transient",
  "message": "Resource was modified since last read",
  "details": {
    "resource_id": "mb_12345",
    "expected_version": 3,
    "current_version": 5
  }
}
```

| キー                 | 型                | 説明                         |
| ------------------ | ---------------- | -------------------------- |
| `resource_id`      | string           | 競合するリソースの識別子               |
| `expected_version` | number \| string | クライアントが操作していたバージョンまたは ETag |
| `current_version`  | number \| string | サーバー上の現在のバージョンまたは ETag     |

### サイズガイダンス

セラーは `details` をコンパクトに保つべきです。エラーレスポンスは LLM コンテキストウィンドウを通じて流れ、すべてのトークンにコストがかかる — リトライをトリガーする一時的なエラーは1つの会話内で複数のエラーレスポンスを蓄積することがあります。ガイドラインとして、`details` を 500 シリアル化 JSON バイト未満に保つ（UTF-8 で `JSON.stringify(details).length` を使用 — 非 ASCII コンテンツには重要だ）。

### `details` スキーマ

推奨される `details` 形式のすべての JSON スキーマはエラーコード列挙と一緒に公開されています:

* [`/schemas/latest/error-details/rate-limited.json`](https://adcontextprotocol.org/schemas/latest/error-details/rate-limited.json)
* [`/schemas/latest/error-details/budget-too-low.json`](https://adcontextprotocol.org/schemas/latest/error-details/budget-too-low.json)
* [`/schemas/latest/error-details/audience-too-small.json`](https://adcontextprotocol.org/schemas/latest/error-details/audience-too-small.json)
* [`/schemas/latest/error-details/account-setup-required.json`](https://adcontextprotocol.org/schemas/latest/error-details/account-setup-required.json)
* [`/schemas/latest/error-details/creative-rejected.json`](https://adcontextprotocol.org/schemas/latest/error-details/creative-rejected.json)
* [`/schemas/latest/error-details/policy-violation.json`](https://adcontextprotocol.org/schemas/latest/error-details/policy-violation.json)
* [`/schemas/latest/error-details/conflict.json`](https://adcontextprotocol.org/schemas/latest/error-details/conflict.json)

これらのスキーマは推奨であり、必須ではありません。`details` を完全に省略するセラーも適合しています。エージェントは特定の `details` キーを要求してはなりません — `details` が欠如または予期しない形状の場合は `code`、`message`、`recovery` にフォールバックします。

## セラー固有のエラーコード

セラーは[標準語彙](https://adcontextprotocol.org/schemas/latest/enums/error-code.json)にないエラーコードを使用してもよい。セラー固有のコードを標準コードと区別し、セラー間の衝突を避けるために:

* セラー固有のコードは `X_{VENDOR}_{CODE}` 形式を使用しなければなりません（例: `X_STREAMHAUS_FLOOR_NOT_MET`）
* `{VENDOR}` はベンダーエラーコードレジストリに登録された大文字英数字識別子でなければなりません（`/^[A-Z][A-Z0-9]{1,19}$/` にマッチ）
* `{CODE}` は大文字英数字とアンダースコアでなければなりません（`/^[A-Z][A-Z0-9_]{1,39}$/` にマッチ）
* エージェントは不明なコードを `recovery` 分類にフォールバックして処理しなければなりません
* 不明なコードで `recovery` が欠如している場合は `terminal` として扱います
* セラーは PR を提出することで[ベンダーエラーコードレジストリ](https://adcontextprotocol.org/schemas/latest/error-details/vendor-error-codes.json)にベンダープレフィックスとコードを登録すべきです

```javascript theme={null}
function handleError(error) {
  if (isStandardErrorCode(error.code)) {
    // Handle per standard code semantics
    return handleStandardError(error);
  }

  // Unknown/vendor code: fall back to recovery classification
  return handleByRecovery(error);
}
```

## クライアントライブラリ要件

この仕様を実装するクライアントライブラリ（`@adcp/client` など）は以下を満たさなければなりません:

1. **構造化エラーを自動的に抽出します。** コンシューマーは、メッセージ文字列の汎用エラーではなく、`code`、`recovery`、`retryAfter`、`field`、`suggestion`、`details` を持つ型付きエラーオブジェクトを受け取るべきです。

2. **検出順序を実装します。** すべてのパスを順番に確認します: `structuredContent`、アーティファクト、`status.message.parts`、`error.data`、テキストフォールバック。

3. **抽出されたエラーを検証します。** `code` が空でない文字列（最大 64 文字）であり、シリアル化されたペイロードの合計が 4096 バイトを超えないことを確認します。検証に失敗したペイロードは破棄します。

4. **テキストフォールバックを `isError` でガードします。** `isError` が `true` の MCP レスポンスでのみ JSON ベースのテキスト抽出を試みる。JSON コンテンツを含む成功レスポンスをエラーとして解釈してはなりません。

5. **リカバリーメタデータを保持します。** 抽出されたエラーには `recovery` と `retry_after` を含め、呼び出し元が再解析なしにリトライロジックを実装できるようにします。

6. **未知のリカバリー値を処理します。** 未知の `recovery` 値は `terminal` として扱います。

7. **`retry_after` をクランプします。** 1 未満は 1 に、3600 超は 3600 になります。非有限値（`NaN`、`Infinity`）は欠如として扱わなければなりません。

8. **テキストフォールバックをサポートします。** `structuredContent` なしの MCP `isError` レスポンスの `content[].text` に対して `JSON.parse` を試みる。`structuredContent` の採用が広まるまで、これが主要な抽出パスになります。

クライアントライブラリは追加で:

* `retry_after` が存在する場合に指数バックオフで `transient` エラーを自動リトライしてもよい
* コンシューマーがリトライ動作を設定するための `retryPolicy` オプションを公開してもよい
* `STANDARD_ERROR_CODES` テーブルを使用して標準エラーコードを型付きエラーサブクラスにマッピングしてもよい

## テストベクター

機械可読のテストベクターは [`/static/test-vectors/transport-error-mapping.json`](https://adcontextprotocol.org/test-vectors/transport-error-mapping.json) で入手可能です。各ベクターには以下が含まれます:

* `transport`: `mcp` または `a2a`
* `path`: 抽出パス（`structuredContent`、`jsonrpc_error`、`text_fallback`、`artifact`）
* `response`: トランスポート固有のレスポンスエンベロープ
* `expected_error`: 抽出されるべき AdCP エラー（またはレガシーサーバーの場合は `null`）
* `expected_action`: `retry`、`surface_to_caller`、`escalate_to_human`、または `generic_error`

クライアントライブラリはこれらのベクターに対して抽出ロジックを検証すべきです。

## エージェントチェーンでのエラー変換

セラーエージェントがアップストリームサービス（API、データベース、他のエージェント）を呼び出す場合、アップストリームの失敗は呼び出し元に返す前に変換しなければなりません。

**ルール 1: アップストリームエラーを AdCP エラーコードに変換します。** 生のアップストリームエラーをそのまま渡してはなりません。セラーの内部 API からの HTTP 429 は `RATE_LIMITED` になります。データベース接続タイムアウトは `SERVICE_UNAVAILABLE` になります。バイヤーは関係のないシステムのエラーフォーマットを見るべきではありません。

**ルール 2: 呼び出し元の視点からリカバリーを分類します。** セラーがバイヤーのアクションなしにアップストリームの問題を修正できる場合、エラーは `transient` または `terminal` だ — `correctable` ではありません。`correctable` エラーは*バイヤー*が何かを変更する必要があることを意味します。例えば: セラーのアップストリームクリエイティブレビュー API が広告を拒否した場合、それは `correctable`（バイヤーはクリエイティブを修正できます）。しかしセラーの内部課金システムがダウンしている場合、アップストリームエラーが 500 であっても、それは `transient`（バイヤーはリトライすべき）だ。

**ルール 3: 中間者は保持するか変換するが、決して削除しません。** バイヤーとセラーの間に座る中間者（例: 複数のセラーにルーティングするエージェンシーエージェント）は以下を行わなければなりません:

* アップストリームがすでに AdCP 準拠の場合は AdCP エラーを**変換せずに渡す**、または
* アップストリームが異なるフォーマットを使用している場合はエラーを有効な AdCP エラーに**変換する**

中間者は渡すエラーから `recovery`、`retry_after`、または `details` を削除してはなりません。中間者は複数のアップストリームセラーからのエラーを `errors` 配列に集約してもよく、各エラーは元の `code` と `recovery` を保持します。

```javascript theme={null}
// Seller-side: translate upstream errors for the buyer
function translateUpstreamError(upstreamError) {
  if (upstreamError.status === 429) {
    return {
      code: 'RATE_LIMITED',
      message: 'Request rate exceeded',
      recovery: 'transient',
      retry_after: upstreamError.headers?.['retry-after'] || 10,
    };
  }
  if (upstreamError.status >= 500) {
    return {
      code: 'SERVICE_UNAVAILABLE',
      message: 'Service temporarily unavailable',
      recovery: 'transient',
    };
  }
  // Never expose upstream details to the buyer
  return {
    code: 'SERVICE_UNAVAILABLE',
    message: 'An internal error occurred',
    recovery: 'transient',
  };
}
```

## セキュリティ上の考慮事項

エラーレスポンスは LLM コンテキストを通じて流れる。すべてのフィールドはクライアント向けです。

### セラーの要件

**実装は以下を含めてはなりません:**

* 内部サービス名、ホスト名、または IP アドレス
* データベースエラーテキスト、SQL フラグメント、またはクエリプラン
* スタックトレースまたはファイルパス
* 内部サービスからのアップストリーム API レスポンス
* 認証情報、トークン、またはセッション識別子

**`suggestion` の境界:** 特定の閾値、有効な識別子、リソースの存在を明かすのではなく、一般的な修正ガイダンス（例: "Increase budget to meet minimum"）を提供します。

**`retry_after` の一貫性:** タイミングサイドチャネルを避けるため、ターゲットリソースのプロパティではなく、呼び出し元のレートリミット状態を反映した一貫した値を返します。

**トランスポートレベルコードの粒度:** 予約済み JSON-RPC コード（`-32029`、`-32028`、`-32027`）はインフラエラーの分類を可能にします。エンドポイントのフィンガープリントを最小化したい実装は、これらを単一のコードに統合してもよい。

### バイヤーエージェントの要件

**エラーフィールドを通じたプロンプトインジェクション。** `message`、`suggestion`、`field`、`details`、およびそれらの中のすべての文字列値は、バイヤーエージェントの LLM コンテキストに入るセラー制御コンテンツです。悪意のある、または侵害されたセラーは、バイヤーエージェントを操作することを目的とした指示を含む値を作成できます。

バイヤーエージェントは以下を行わなければなりません:

* **すべてのリカバリー決定を `code` と `recovery` のみを通じてルーティングします。** アクション可能な指示のために `message`、`suggestion`、または `details` 値を解析してはなりません。上記の `handleAdcpError` 関数はこのパターンを示している — メッセージコンテンツではなく `recovery` で切り替える。
* **セラー提供の文字列にデータ境界を使用します。** エラーフィールド値を LLM コンテキストに含める場合、システムプロンプトが信頼できないセラーデータとして指定する明示的なデータデリミター（例: 構造化されたツールレスポンスフィールド、XML スタイルタグ）の内側に置く。セラー提供の文字列を散文や指示に補間しません。
* **セラー文字列を LLM コンテキストに含める前に長さ制限を適用する:** `message`（256 バイト）、`suggestion`（512 バイト）。サイレントにトランケートします。
* **すべての文字列フィールドから非印刷可能文字を除去する:** 制御文字（U+0000–U+001F）、ゼロ幅文字（U+200B–U+200F）、双方向オーバーライド文字（U+202A–U+202E）。
* **最大ペイロードサイズを強制します。** クライアントは `JSON.stringify(error).length` が 4096 バイトを超える抽出された `adcp_error` オブジェクトを破棄しなければなりません。これにより過大な `details` オブジェクトによるコンテキストウィンドウの消耗を防ぐ。
* **オブジェクトミューテーション操作でダイナミックプロパティパスとして `field` を使用しない**（例: `lodash.set`、ブラケット表記チェーン）。`field` 値は表示とフィールドレベルの UI ハイライトのみ用です。
* **キーをフィルタリングせずに `Object.assign`、スプレッド演算子、またはシャローコピーを通じて抽出されたエラーオブジェクトをアプリケーション状態にマージしません。** `__proto__` や `constructor` などのセラー制御キーは一部のランタイムでプロトタイプ汚染を引き起こす可能性があります。
* **生の `details` オブジェクトをシステムプロンプトやツールの説明に含めない。**

**URL 検証。** `details.setup_url`（`ACCOUNT_SETUP_REQUIRED` エラー内）は、アカウントセットアップを完了するためにユーザーまたはエージェントが辿ることができるセラー提供の URL だ。クライアントは `setup_url` が `https` スキームを使用し、ユーザー情報コンポーネントを含まず（例: `https://user:pass@evil.com`）、ドメインがセラーの既知のドメインと一致することを検証しなければなりません。これらの確認に失敗した URL は拒否しなければなりません。

`details.policy_url`（`CREATIVE_REJECTED` および `POLICY_VIOLATION` エラー内）は情報提供のみです。クライアントは同じ検証を適用すべきです。すべてのセラー提供 URL は `https` 以外のスキーム（`http`、`javascript`、`data`、`file`）を使用している場合は拒否しなければなりません。

## 関連情報

* [エラーハンドリング](/docs/building/by-layer/L3/error-handling) — エラースキーマ、標準コード、リカバリー戦略
* [MCP ガイド](/docs/building/by-layer/L0/mcp-guide) — MCP トランスポート統合
* [A2A ガイド](/docs/building/by-layer/L0/a2a-guide) — A2A トランスポート統合
* [A2A レスポンスフォーマット](/docs/building/by-layer/L0/a2a-response-format) — 標準 A2A レスポンス構造
