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

# GraphQL エラー

> Ayrshare GraphQL API がエラーを報告する方法。不正なリクエストに対する HTTP ステータスコードから、errors 配列、部分的な成功、冪等な再試行、レート制限まで。

<h2 id="resolver-errors-arrive-with-http-200">
  リゾルバーのエラーは HTTP 200 で返される
</h2>

これは、エラー処理を書く前に知っておくべき最も重要な点です。

GraphQL over HTTP 仕様に従い、リゾルバーに到達したリクエストは、**操作が失敗した場合でも HTTP 200** を返します。失敗はステータスコードではなく、レスポンスボディの中で報告されます。

そのため、次のチェックは機能しません:

```javascript theme={"system"}
// WRONG - will treat a failed request as a success
if (response.ok) {
  return "everything worked";
}
```

代わりにボディを確認してください。サポートされていない `Content-Type` に対する 415 など、一部のトランスポートエラーはボディが空であるため、パースする前にレスポンスが JSON であることを確認してください:

```javascript theme={"system"}
if (!response.headers.get("content-type")?.includes("json")) {
  throw new Error(`GraphQL request failed with HTTP ${response.status}`);
}

const result = await response.json();

if (result.errors) {
  for (const error of result.errors) {
    // Errors caught before execution have no extensions, so read it safely.
    console.log(error.message, error.extensions?.status);
  }
}
```

一部の失敗は、何かが実行される前に検出されます。これらはいずれもリゾルバーに到達せず、API 呼び出しも消費しません:

<ul class="custom-bullets">
  <li>不正なリクエストはエラーステータスを返します。無効な JSON または <code>query</code> の欠落には <strong>HTTP 400</strong>、64 KB を超えるボディには <strong>413</strong>、<code>POST</code> 以外のメソッドには <strong>405</strong>、サポートされていない <code>Content-Type</code> には <strong>415</strong> が返されます。</li>
  <li>スキーマに対して無効なクエリは、リクエストで <code>Accept: application/graphql-response+json</code> を送信した場合にのみ <strong>HTTP 400</strong> を返します。これには、構文エラー、不明なフィールド、誤った引数の型、無効な列挙値、<a href="/docs/apis/graphql/limits#query-limits">クエリの制限</a>を超えるクエリが含まれます。<code>Accept: application/json</code> を送信した場合、または <code>Accept</code> ヘッダーを送信しない場合、同じエラーは <strong>HTTP 200</strong> を返します。いずれの場合も、ボディには <code>errors</code> 配列が含まれ、<code>data</code> は含まれません。</li>
</ul>

実行が始まると、リゾルバーレベルの入力検証や API の失敗（認証、認可、上流のレート制限、上流の 5xx レスポンスを含む）は、`errors` 配列付きの HTTP 200 を返します。

<h2 id="the-error-shape">
  エラーの形式
</h2>

すべてのリゾルバーエラーは、HTTP に相当する API ステータスを `extensions` に含んでいます:

```json theme={"system"}
{
  "data": { "postHistory": null },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["postHistory"],
      "extensions": {
        "status": 429,
        "retryAfter": 7
      }
    }
  ]
}
```

<ul class="custom-bullets">
  <li><code>message</code> — 人が読める説明。リゾルバーのエラーメッセージからは API キーやその他の認証情報が削除されますが、誤った型の変数など、送信した値に関するエラーではその値が含まれる場合があります。ログに記録する前に、<code>message</code> は機密情報を含む可能性があるものとして扱ってください。</li>
  <li><code>path</code> — クエリ内のどのフィールドが失敗したか。1 回のリクエストに複数のフィールドがある場合、これでどのフィールドかを判別します。</li>
  <li><code>extensions.status</code> — 同等の REST 呼び出しが返したであろう HTTP ステータス。これで分岐してください。</li>
  <li><code>extensions.code</code> — 内部のエンドポイントが提供する場合の、Ayrshare の数値エラーコード。</li>
  <li><code>extensions.retryAfter</code> — 再試行までの待機時間が利用可能な場合に、上流のクォータまたはレート制限による 429 に含まれます。リクエストごとのディスパッチ予算による 429 には含まれません。</li>
</ul>

`extensions.code` は[エラーコードリファレンス](/docs/errors/overview)と合わせて使用するか、`explainError` に渡してください。

<h2 id="partial-success">
  部分的な成功
</h2>

リクエストで複数のものを要求し、その一部だけが成功した場合、`data` と `errors` の**両方**が返されます:

```graphql theme={"system"}
{
  history: postHistory(lastDays: 7)
  analytics: socialAnalytics(platforms: [INSTAGRAM])
}
```

```json theme={"system"}
{
  "data": {
    "history": { "history": [{ "id": "RkQ8uXg2jT7bNd1Wq0Ya", "status": "success", "post": "Hello world" }], "refId": "9d2a7c41f0b8e6d35a1c", "count": 1, "lastUpdated": "2026-09-24T12:00:00.000Z", "nextUpdate": "2026-09-24T12:00:00.000Z" },
    "analytics": null
  },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["analytics"],
      "extensions": { "status": 429 }
    }
  ]
}
```

`history` は成功しており、そのデータは使用できます。再試行が必要なのは `analytics` だけです。`errors` が存在するからといってレスポンス全体を破棄しないでください。すでに課金されたデータを捨てることになります。

<h2 id="partial-success-on-multi-network-posts">
  複数のソーシャルネットワークへの投稿における部分的な成功
</h2>

複数のソーシャルネットワークへの投稿は、一部で成功し、他で失敗することがあります。これは GraphQL のエラーとしては**報告されません**。操作自体は機能しており、要求どおりのことを実行したうえで、何が起こったかを伝えているためです。

結果は 3 つの結果を区別します:

```graphql theme={"system"}
mutation {
  createPost(input: {
    post: "Hi"
    platforms: [FACEBOOK, INSTAGRAM]
    idempotencyKey: "multi-network-hi-001"
  }) {
    status
    postIds { platform postUrl }
    errors { platform message code }
    blocked { platform message }
  }
}
```

<ul class="custom-bullets">
  <li><code>postIds</code> — 公開されたソーシャルネットワークと、その投稿 URL。成功したもののみです。</li>
  <li><code>errors</code> — 失敗したソーシャルネットワークと、その理由。</li>
  <li><code>blocked</code> — 試行の前に停止されたソーシャルネットワーク。たとえば、決定的な失敗が繰り返された後にソーシャルネットワークごとのサーキットブレーカーによって停止された場合です。これらは、プロバイダーへの試行がエラーを返したものとは区別されます。</li>
</ul>

**いずれか**のソーシャルネットワークが失敗すると `status` は `"error"` になるため、何も公開されなかったことを示す信頼できるシグナルではありません。実際に何が公開されたかは `postIds` を確認してください。

<h2 id="retries">
  再試行
</h2>

**GraphQL API が自動的に再試行することはありません。** リクエストが失敗した場合、あなたの代わりに暗黙的に再試行されたものは何もありません。

これは特にミューテーションで重要です。`createPost` は `idempotencyKey` を公開しています。最初の試行の前に一意のキーを生成し、再試行のたびに同じキーとまったく同じペイロードを再利用してください。確定済みのリクエストを再試行すると、書き込みを繰り返す代わりに元の結果が再生されます。あいまいなレスポンスを受け取った後に新しいキーに切り替えないでください。

`boostFacebookPost` と `instagramBoostPost` も `idempotencyKey` を受け取り、これは実際の費用を保護します。同じキーと同じ引数で再試行すると、2 つ目の広告を作成して支払う代わりに、`idempotentReplayed: true` が付いた元の結果が返されます。1 つのキーは両方の Meta プラットフォームにわたってアカウント全体をカバーするため、Facebook のブーストのキーを Instagram のブーストに再利用しないでください。

キーが拒否された場合、`extensions.status` でその理由がわかります。`createPost` は、最初の試行がまだ処理中の場合は 409 を返すので、待ってから同じキーで再試行してください。ペイロードが最初の試行と異なる場合は 400 を返します。ブーストのミューテーションは、どちらの場合も 409 を返し、キーがもう一方のプラットフォームのブーストに使用されていた場合も 409 を返します。

`addComment` など、その他の書き込みには冪等キーがありません。レスポンスが失われた場合は、再度試行しても安全かどうかを判断する前に、ソーシャルネットワークまたは API の状態を確認してください。

2 つの異なる制限がどちらも 429 を報告し、それぞれ異なる対処が必要です。ディスパッチ予算は、同じリクエスト内ですでに 5 回の API 呼び出しが開始された後にのみルートフィールドを拒否し、そのメッセージは `Query exceeds the per-request dispatch budget` で始まります。これらのフィールドを 5 つ以下のリクエストに分割してください。待つ必要はありません。それ以外の 429 はレート制限またはクォータです。`extensions.retryAfter` が存在する場合はその秒数だけ待ち、存在しない場合はバックオフしてから再試行し、失敗したフィールドのみを再試行してください。**読み取り**での 5xx は再試行しても安全ですが、例外が 1 つあります。`generatePost` はクエリですが、再試行すると AI ジェネレーターが再び呼び出され、別の API 呼び出しとしてカウントされ、異なるテキストが返されます。冪等性のない書き込みでの 5xx の場合は、再試行する前にそれが反映されたかどうかを照合してください。

<h2 id="common-statuses">
  一般的なステータス
</h2>

| `extensions.status` | 意味 | 対処方法 |
| - | - | - |
| 400 | API が拒否した無効な入力 | リクエストを修正してください。再試行しても解決しません |
| 401 | API キーがない、または無効 | `Authorization` ヘッダーを確認してください |
| 402 | プランにこの機能が含まれていない | プランを確認してください |
| 403 | キーは有効だが、この操作は許可されていない | Profile Key とプランを確認してください |
| 404 | 要求したものが存在しない | ID を確認してください |
| 409 | 冪等キーが使用中: 最初のリクエストがまだ実行中であるか、ブーストのキーが異なる引数で使用された | 最初のリクエストがまだ実行中の場合は、待ってから変更せずに再試行してください。それ以外の場合は、新しい操作に新しいキーを使用してください |
| 429 | レート制限、クォータ、またはディスパッチ予算 | メッセージにディスパッチ予算が示されている場合は、リクエストを分割してください。それ以外の場合は `retryAfter` だけ待つか、存在しない場合はバックオフしてください |
| 500 | こちら側で問題が発生した | 読み取りは再試行してください（再度課金される `generatePost` は除く）。サポートされている場合は同じ冪等キーを再利用し、それ以外の場合は再試行する前に書き込みを確認してください |

不明なフィールド、誤った引数の型、無効な列挙値など、実行前に GraphQL 自体が発生させるエラーには `extensions.status` がありません。上述のとおり、`Accept` ヘッダーに応じて HTTP 400 または 200 を返します。これらはクエリ自体が誤っていることを意味し、API 呼び出しは行われず、課金もされません。
