要点を1行で言うと: 生のレスポンスボディ を返された内容のまま正確に表示してください。プログラムが包んだ1行の文字列だけを残してはいけません。
400 Bad Request のような文字列は診断にほとんど役立ちません。本当の答えは、それが捨てた JSON の中にあります。実例: 400 Bad Request では何も分かりません
あるお客様から、たった 1 行だけの報告がありました:400 は通常、コンテンツ安全性かパラメータの問題のいずれかです。おそらくコンテンツ安全性です。これは 推測 であって、結論ではありません。というのも、まったく同じ呼び出しでも、実際のレスポンス本文は次の 3 つのいずれかだった可能性があり、それぞれで取るべき対応はまったく異なるからです:
バックエンドログにあるもの・ないもの
まず押さえるべき考え方は、バックエンドログはエラーログではなく、課金台帳です。保持すべき 7 つの項目
失敗した 1 回の呼び出しを診断するには、これで十分です。どれか 1 つでも欠けると、診断は推測に逆戻りします。レスポンスボディを切り詰めないでください。 200 文字に切り詰めるのは通常の業務ログとしては妥当ですが、診断では重要な情報が末尾にあることがよくあります。少なくとも先頭の 2000 文字は残してください。画像エンドポイントで base64 がログを大量に埋めるのが心配なら、
status_code >= 400 のときだけ全文を出力してください。エラーボディはたいてい短いです。エラー捕捉パターンを正しくする
原則は実質 1 つだけです: 2 層で捕捉し、どちらの層でも何も捨てないことです。- トランスポート層の失敗: 接続リセット、TLS ハンドシェイク失敗、タイムアウト、DNS 失敗。HTTP 応答はまったくありません — 取得できるのは例外テキストだけです。
- HTTP 層のエラー: サーバーが 4xx / 5xx を返しました。レスポンスボディがあり、必ずそれを読み取る必要があります。
Python / requests
Python / OpenAI SDK
公式 SDK は、3 つの要素をすでに例外オブジェクトに付与しています。多くの人は代わりに、自分の 1 行メッセージをprint してしまいます:
Node.js
SDK では:fetch では、ここで最もよく失敗します:
cURL で再現する
誰かに問題の再現を依頼するとき、このコマンドが最小の手間です — ステータスコード、ヘッダー、ボディ、時間を一度に表示します:-iはレスポンスヘッダーを表示します。x-request-idがあるのはそこです;-sSは進行状況バーを隠しつつ、エラー出力は保持します;-wはステータスコードと合計時間を付け足します。タイムアウト設定との比較に便利です。
ラッパーと社内ゲートウェイ
よい例
このエラーは、お客様の ComfyUI ノードから発生しました:400 Bad Request よりはるかに見た目は悪いですが、それでも 完全 なので、原因の方向性は数秒で絞れます:
結論はすぐに分かります。これは トランスポート層 の問題であり、コンテンツの安全性やパラメータとは無関係で、課金も発生しません(リクエストが最後まで完了していないためです)。トラブルシューティングの手順: 画像 API の接続切断。
2 つを比べてください: 一方はきれいにまとまっているのに何も説明しておらず(
400 Bad Request)、もう一方は長くて見苦しいものの、根本原因をまっすぐ示しています(errno 10054)。診断では、手を加えて整えた親切なエラーより、むき出しで見苦しくても完全なエラーのほうが常に優れています。一般的なツールで生の出力を見つける場所
社内ゲートウェイの 3 つのルール
1
そのまま通し、決して書き換えない
中間層はコンテキスト(どのサービスか、どのテナントか、何回目のリトライか)を 追記 しても構いませんが、上流の
error.message を 置き換えてはなりません。一度書き換えると、元の情報を取り戻せる場所はもうありません。2
ユーザー向けメッセージを生のものと分けて保存する
Gemini の画像エラー処理 で使われている 3 要素構成に従ってください:
userMessage(エンドユーザー向けの親しみやすい文面)、devMessage(開発者向けの分類)、rawResponse(変更せずそのままのレスポンス本文)です。最初の 2 つは自由に整え、3 つ目はそのまま保存してください。3
不明なエラーを返さない
フォールバック分岐では、
status、x-request-id、そして本文の最初の 2000 文字を記録してください。元のテキストを含む「未分類エラー」なら診断できますが、きれいな「不明なエラー」では診断できません。診断を不可能にするアンチパターン
except Exception as e: print("request failed")— 例外オブジェクトが失われ、どのレイヤーが失敗したのかもわかりません。- status code だけを記録して body を記録しないこと — まさにこのページの冒頭のケースです。
- 先に
resp.textを読まずにraise_for_status()を呼び出すこと — メッセージはまだメモリ上にあるのに、取得されないままです。 if (!resp.ok) throw new Error(resp.statusText)infetch— body は response オブジェクトと一緒に破棄されます。- 成功した再試行のあとにきれいな 200 だけを残すこと — 各試行を個別にログしてください。そうしないと、transport が何回失敗したのか見えず、自分の再試行を gateway の挙動と誤認するおそれがあります。
- stdout のみにログを出す、または毎日上書きでローテーションすること — 顧客が問題を報告するころには、元の記録はたいてい流れ去っています。
- 画面の写真をスマホで撮って問題を報告すること — 代わりに テキスト を貼り付けてください。スクリーンショットではエラーの 1 行の半分がよく切れてしまいます。
サポートに連絡すべき場合
まずは上記のキャプチャと解釈の手順を進めてください。以下のいずれかに当てはまる場合は、資料をサポートにお送りください。- 完全なレスポンス本文と
error.messageが上流に示されている(upstream_error、生の上流 5xx、または明示的なチャネルエラー); - 同じリクエストパラメータが別のモデルや別の時刻では動作し、特定の 1 つのモデルだけが一貫して失敗する;
- エラーが
500+write_response_body_failed、または同様の下流配信失敗であり、しかも一貫して再現する(これらは課金されません。接続の切断 を参照してください); - 実際の呼び出し内容と課金が一致していないと疑っており、正確に突き合わせられる唯一の手がかりが
request_idである。
サポートチケットのテンプレート(コピー&ペースト)
WeCom サポート

@apiyi001、またはメールアドレス [email protected] でもご連絡いただけます。関連ドキュメント
API マニュアル
よくあるエラーコード、認証、レート制限
接続切断
ECONNRESET、errno 10054、SSL EOF に関する完全なトラブルシューティング手順ログ照会 API
API で呼び出しログを取得する —
request_idの確認方法と課金の照合方法課金額の読み方
失敗した呼び出しがログに残らない理由と、それを診断テストとして使う方法
タイムアウト設定
モデル種別ごとのタイムアウト階層と、延長しても改善しない場合に確認する点
画像 API の基本
同期呼び出し、base64 プレフィックスの違い、
400 invalid_image_file の前処理