当社独自のアクセス統計は常に有効です。Google Analyticsは、公開ページ(ログイン後のワークスペースは対象外)の利用状況を把握するためのもので、許可をいただいた場合のみ有効になります。詳しくは プライバシーポリシーをご覧ください。

APIエラーへの対処:401、422から限定的な自己修復まで

認証、認可、機能、パラメータ、不明な結果を区別し、最新のディレクトリを使ってリクエストを修正します。さらに、ネットワークリクエストを送信しない判定エンジンでリトライを制限し、エラー処理が無許可の権限昇格や重複呼び出しにつながるのを防ぎます。

リクエストが失敗したとき、クライアントがまず問うべきは「あと何回試せるか」ではなく、「この処理は実行されたのか、リトライに意味を持たせるには何を変える必要があるのか」です。キーの欠落、誤ったプラットフォーム名、サポートされていないパラメータ、レスポンスのストリーミング中の接続切断は、どれもまったく同じcatchブロックに入る可能性があります。これらを一律にリトライすると、修正できるはずの入力が失敗を繰り返し、すでに作成されたタスクが重複することさえあります。

この記事では、EveryInfraのRESTインターフェースを例に、エラーの階層化、ディレクトリの確認、限定的な自己修復の方法を説明します。サンプルの判定エンジンは次の手順の推奨を返すだけで、リクエストの送信、認証情報の切り替え、データ範囲の自動拡大は一切行いません。現在のソースコード、無料の公開プローブ、過去の業務サンプルはそれぞれ分けて使い、1つの400レスポンスから認証済みの場合の失敗動作をすべて推測することは避けます。

エラー分析前の試行の記録

呼び出しの前に業務オペレーションIDを生成し、同じ意図による複数の試行を関連付けます。試行ごとに、開始・終了時刻、リクエストのバージョン、対象の機能、HTTPステータスコード、取得できる場合はサービスのリクエストIDを保存します。業務IDはサーバーの冪等キーではありません。サービスがサポートを明示していない場合、そのIDを付けて再送すれば重複が排除されるとは想定できません。

レスポンスボディは、HTML、プレーンテキスト、空のコンテンツ、または解析できないJSONの場合があります。エラーを解析する前に、Content-Typeとステータスを確認してください。解析に失敗した場合は最小限の診断サマリーを残し、生のエラーページをそのままユーザーのプロンプトに書き込んだり、指示としてエージェントに渡したりしないでください。デフォルトでは、ログにキー、署名付きURLの全体、生のボディ、その他不要な個人データを含めません。

現在のEveryInfraの公開エラーエンベロープには、error.code、error.message、error.request_idが含まれます。処理はコードとHTTPステータスを軸に組み立て、メッセージは人が読むためのテキストとして扱ってください。英語のメッセージが変わらないことを前提にせず、文字列内で最初に見つかったURLへ認証情報を付けたまま自動的に移動することもしないでください。

診断ログの許可リストを作成する際は、OWASP Logging Cheat Sheetを参照できます。インタラクション識別子を使ってイベントを関連付け、トークン、セッション値、機密情報をマスクします。エラーログには試行を特定するのに十分なコンテキストを含める一方で、認証情報や顧客データのコピーを入手できる別の情報源にならないようにします。

401と403:認証と認可の個別処理

HTTP 401は有効な認証情報がないことを、403はサーバーがリクエストを拒否したことを示します。プロトコルのステータスは一般的な意味を示すだけで、具体的な原因はプロダクトのエラーコードで判断します。EveryInfraの現在の実装では、キーの欠落、無効、期限切れは認証の問題であり、プロダクト、細かな機能単位、送信元IPに対する制限は認可の問題です。

まず、リクエストが正しいサービスに届いているか、Authorizationヘッダーがサービスの要件に合っているか、実行中のプロセスが想定どおりの環境を読み込んでいるかを確認します。シークレットを出力せずに、変数の有無と設定フラグを確認してください。ブラウザでコンソールにログインしているからといって、サーバー側のプロセスが正しいAPIキーを取得できているとは限りません。

認証の失敗が続く場合は、影響を受けるタスクを一時停止して担当者に通知します。復旧のために別のキーを順に試したり、アカウントを切り替えたり、権限の制限を無効にしたりしないでください。自動更新は、プロダクトがサポートし、明示的に許可されたフローにのみ適用されます。有効期間の長いAPIキーを、自動で更新できるトークンとして扱うことはできません。

機能名の誤り:候補の事前確認と対象の検証

キー不要の公開エラーは、次のように確認できます。ここでは、場所のレビューは収集せずディレクトリだけを読むために、廃止されたgoogle_mapsの識別子をあえて渡しています。

不明なプラットフォームのステータスとエラーボディの確認
curl --silent --show-error --include --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=google_maps'

2026-09-04 20:46(北京時間)時点の結果はHTTP 400で、error.codeはunknown_capabilityでした。メッセージにはgoogle_maps_reviewsと、類似する別の候補が含まれています。不明な機能を一律に404に対応付けることはできません。また、候補が最上位になったというだけで、元のタスクを自動的に切り替えるべきでもありません。

元のタスクが場所のレビューを対象としている場合は、google_maps_reviewsがレビューを提供しているか、どのようなURL構造を必要とするか、出力が元の要件を満たすかを確認してください。候補のマッチングアルゴリズムが解決するのは名前の類似性だけで、ビジネス上の意図は理解しません。アプリストアのレビューと場所のレビューは、互いに置き換えられるデータではありません。

422:現在のパラメータに合わせた入力の修正

422は一般に、リクエストの内容は理解できたものの、含まれる指示を処理できないことを示します。アプリケーションでは、さらにフィールドの欠落、不明なフィールド、無効な列挙値、サイズ制限を区別する必要があります。それぞれ対処方法が異なります。URLが欠けている場合は実際の対象が必要です。不明なソートオプションにはパラメータの検証が必要です。入力が大きすぎる場合は、元の資料の半分を黙って切り捨てるのではなく、確認済みの分割方法を使う必要があります。

特定のプラットフォームに絞ったパラメータの確認
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=douyin' \
  | jq '[.capabilities[] | {
      action, required_params, optional_params, param_meanings, max_limit
    }]'

現在の実装では、不明なパラメータにはunknown_param、サポートされていない列挙値にはinvalid_valueを返し、対処のヒントを添えます。ただし、同じ名前のパラメータでもアクションによって異なる場合があるため、全体共通のパラメータ表で各アクションのパラメータリファレンスを代替することはできません。required_params、optional_params、許可される値はあわせて確認する必要があり、一般的なリストの上限はページネーションを保証するものではありません。

修正後は新しいリクエストバージョンを作成し、元のエラーと変更理由を残します。マッピングを自動で適用するのは、元の意図が明確に保たれる場合だけにしてください。候補が複数ある、実際の対象がない、期間が広がる、モデルが変わるといった場合は、人による判断が必要です。欠けているフィールドをモデルの推測で埋めることは、安全な自己修復ではありません。

402と429:クォータの問題とレート制限の区別

EveryInfraでは現在、クォータ不足を示すために402 quota_exhaustedを使用しています。これはプロダクト固有の取り決めであり、すべてのサービスに共通する402の業務上の意味ではありません。クォータの問題にはアカウント所有者による対応が必要です。同時実行数を下げても残高が自動的に増えることはなく、クライアントが自動でチャージしたり認証情報を切り替えたりしてはいけません。

429はレート制限のシグナルです。レスポンスに有効なRetry-Afterヘッダーが含まれていれば、その指示に従ってください。ヘッダーがないからといって、すぐに間隔を詰めて再試行してよいわけではなく、サービスの復旧時刻を推測で作り出してよいわけでもありません。再試行の間隔、ジッター、最大試行回数、期限は、アプリケーションのポリシーで明示的に定義する必要があります。

レート制限の戦略は、同じクォータを共有するすべてのワーカープロセスを対象にする必要があります。1つのワーカーだけがバックオフしても、他のワーカーが送信を続ければ輻輳は解消しません。このガイダンスはアプリケーション側のスケジューリングに関するもので、APIが複数のクライアントプロセスを代わりに調整することを意味するものではありません。

5xxエラー、切断、送信済みタスク:まず実行状態を確認

5xxエラーを単純に「何も起きなかった」と解釈することはできません。サービスがリクエストを受け付けた、部分的な結果を生成した、あるいは課金処理を完了したにもかかわらず、クライアントが完全なレスポンスを受け取れていない可能性があります。明示的な冪等性の保証や実行の証拠がない場合は、POSTを自動で再送せず、結果を不明として記録し、リクエスト識別子で確認してください。

job_idやサービスが提供する照会用エンドポイントが利用できる場合は、元のタスクの照会を優先してください。実行中、終了処理中、成功、失敗、照会の失敗はそれぞれ区別して扱う必要があります。照会結果が404の場合は認証主体やスコープの問題である可能性があり、代わりのタスクを作成するきっかけにしてはいけません。照会には元のリクエストに対応する認証主体を使用していることを確認してください。

HTTP 200が返った後も、業務上の内容は確認する必要があります。MCPにはJSON-RPCとツールエラーという層が加わるため、RESTだけを前提とした戦略には頼れません。空の結果セット、部分的な結果、異常なレスポンスはそれぞれ固有の状態として保持し、一律に成功として扱いません。また、最終的な課金額をクライアント側の状態だけから導き出すことはできません。

MicrosoftのRetryパターンは重要な注意点を示しています。再試行するのは回復可能な障害のみとし、操作の冪等性と再試行層の重なりを考慮することです。SDK、キュー、業務レイヤーがそれぞれ独立して再試行すると、総試行回数が予算を超える可能性があります。あらゆる場所で「もう一度試す」を既定にするのではなく、全体の文脈を把握している1つの層が判断を担うべきです。

再試行を実行せずにルーティングする判定エンジン

以下はオフラインのアプリケーション層の例であり、EveryInfraのSDKではありません。入力は、プロトコルの解析を完了したRESTの試行記録から取得する必要があります。retry_after_policy_checkは、実際のインターフェース上の取り決めや未実行であることの明確な証拠に基づいて設定する必要があり、モデルやエラーテキストによって任意に有効化してはいけません。attemptsはそれまでの試行回数を表します。

オフラインJavaScript:認可ゲートと再試行予算の維持
function nextStep({status, hasJob = false, replaySafe = false,
                   attempts = 1, maxAttempts = 3}) {
  if (status !== null && (!Number.isInteger(status) || status < 100 || status > 599)) {
    throw new Error("invalid HTTP status");
  }
  if (typeof hasJob !== "boolean" || typeof replaySafe !== "boolean"
      || !Number.isSafeInteger(attempts) || attempts < 1
      || !Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
    throw new Error("invalid decision inputs");
  }
  if (status === 401 || status === 403) return "authorization_review";
  if (status === 402) return "account_review";
  if (hasJob) return "inspect_existing_job";
  if (status === 400 || status === 422) return "revise_request";
  if (status === 429 || status === null || (status >= 500 && status <= 599)) {
    return replaySafe && attempts < maxAttempts
      ? "retry_after_policy_check"
      : "inspect_attempt";
  }
  if (status >= 200 && status < 300) return "validate_delivery";
  return "manual_review";
}

// synthetic attempt; contains no network calls.
console.log(nextStep({status: 503}));
console.log(nextStep({status: 429, replaySafe: true, attempts: 3}));
console.log(nextStep({status: 202, hasJob: true}));

3つの出力は、それぞれ現在の試行の確認、予算を使い切った後の試行の確認、元のタスクの照会が必要であることを示します。retry_after_policy_checkは即時に再試行する命令ではありません。外側の層では、待機時間、グローバルなレート制限、ユーザーが許可した操作範囲も確認する必要があります。パラメータを調整して新しい試行を作成した場合も業務全体の予算に計上され、カウンターをリセットして無限にループさせてはいけません。

復旧の検証と同等に重要な停止の検証

  • 無効な認証:別の認証情報にアクセスせず、業務上の再試行も行いません。
  • 機能の候補が曖昧な場合:元の対象を保持し、確認を求め、製品の自動切り替えを防ぎます。
  • リクエストは受け付けられたがレスポンスが中断された場合:元の試行とタスクを保持し、重複して作成しません。
  • パラメータ修正後も失敗が続く場合:新しいバージョンを記録しつつ、全体の試行予算を守ります。
  • JSON以外のエラー、リクエストIDの欠落、未知のコード:クラッシュしたり成功を捏造したりせず、保守的な処理に移行します。
  • 利用可能なデータは返されたが業務上の目標を満たさない場合:配信状態と残課題を保持し、残高の回復を一方的に宣言しません。

少数のエラーサンプルを用意しておき、SDKのアップグレード時、APIパラメータの変更時、認証戦略の変更時に再実行してください。ソースのテストは想定どおりのシーケンスを検証しますが、本番環境へのデプロイには、範囲を限定した実入力による証拠が必要です。それぞれの日付は別々に記録してください。古いスクリーンショットや無料のディレクトリで得たエラーを、当日の認証済みの業務受け入れ確認の代わりにしてはいけません。

安全な自己修復の目的は、明らかに修正できる問題で人の手を煩わせる回数を減らしつつ、本当に判断が必要な場面では速やかに実行を止めることです。各ステップで、エラーがどこで発生したか、何が変わったか、実行が行われたか、次のステップがなぜ許可されるのかが明確であれば、エラーメッセージは無限の再試行のきっかけではなく、実際に連携を助けるものになります。

参考資料 LF-12