API エラーコード
本サイトが返すすべての失敗を、2026-09-01に実際のエンドポイントへ 1 件ずつ投げて確認したものです。返ってくる 7 件のうち 5 件はステータスコードが本当の原因を指しておらず、そのうち 2 件は公式 SDK が黙って再試行するため、プログラムに届くのはさらに後になります。
2026-09-01 検証
ステータスコードが実際の原因と異なる
ステータスコードではなく error.code を読む
モデル名の誤りは 503、messages フィールドの欠落は 500で返ってきます。どちらもリクエスト自体の誤りで、何度再試行しても結果は変わりません。ところが openai-python、openai-node、Anthropic の各 SDK はいずれも 408・409・429と 5xx 全般を既定で 2 回、指数バックオフ付きで再試行します。つまり 1 か所のタイプミスが 3 往復と数十秒の待ち時間に変わり、そのあとで最初から確定していた原因がようやく表示されます。本当の原因は最初からレスポンスボディの error.code にあり、嘘をついているのはステータスコードの側です。
一覧
ステータスコード
数値順ではなく、実際に遭遇する頻度の順に並べています。
- HTTP 401
空文字列- 実際に起きていること
- キーが存在しない、すでに失効している、または Authorization ヘッダー自体が付いていません。
- 対処方法
- コンソールの「API キー」ページでキーが残っているか確認し、必要なら新しく発行してください。なお "Bearer " の付け忘れは原因になりません——本サイトはキーだけの形式も受け付けます。
- SDK の再試行
- しない(即座に失敗)
- 実際のエンドポイントで計測
- probes-errors.mjs: invalid-token / missing-auth
返されたメッセージ Invalid token - HTTP 503
model_not_foundステータスコードが実際の原因と異なる- 実際に起きていること
- そのモデル ID は本サイトのカタログにありません。ほとんどの場合、他社のドキュメントから写したもの(gpt-4o、claude-sonnet-4-5)です。障害ではなく、存在しないモデルに割り当てる経路がないだけです。
- 対処方法
- GET /v1/models の結果と照合してください。それが唯一の正式な一覧です。本サイトの ID は必ず ベンダー/モデル の形式で、例えば deepseek/deepseek-v4-flash です。
- SDK の再試行
- する(既定で 2 回)
- 実際のエンドポイントで計測
- probes-errors.mjs: unknown-model
返されたメッセージ No available channel for model gpt-4o under group y-api (distributor) - HTTP 403
insufficient_user_quotaステータスコードが実際の原因と異なる- 実際に起きていること
- アカウント残高がゼロになりました。このメッセージは中国語で、残高には全角の $ が使われています。英語で検索しても何も出てこないのはそのためです。
- 対処方法
- https://y-api.bestvirtualgoods.com/app/billing で入金してください。クレジットは即時に回復し、既存のキーはそのまま使えます。コードの変更も不要です。
- SDK の再試行
- しない(即座に失敗)
- 上流のソースコードで確認(本サイトでは未発生)
- service/billing_session.go:355-359
返されたメッセージ 用户额度不足, 剩余额度: $0.00 - HTTP 403
pre_consume_token_quota_failedステータスコードが実際の原因と異なる- 実際に起きていること
- アカウントには残高がありますが、このキー 1 本が作成時に設定した上限に達しました。メッセージにはそのキーの残額と、今回のリクエストに必要だった額の両方が示されます。
- 対処方法
- 「API キー」ページでそのキーの上限を引き上げるか解除するか、上限のないキーに切り替えてください。アカウントへの入金では解決しません——上限はキー単位です。
- SDK の再試行
- しない(即座に失敗)
- 実際のエンドポイントで計測
- probes-errors.mjs: quota-exhausted
返されたメッセージ token quota is not enough, token remain quota: $0.000002, need quota: $0.000074 - HTTP 500
invalid_requestステータスコードが実際の原因と異なる- 実際に起きていること
- リクエストボディに必須フィールドがありません。多いのは messages です。本来 400 系のリクエストエラーであるものが、サーバーエラーとして返っています。
- 対処方法
- メッセージにフィールド名がそのまま出るので、ステータスコードではなくそちらを読んでください。ボディを直すこと。再試行しても同じ結果です。
- SDK の再試行
- する(既定で 2 回)
- 実際のエンドポイントで計測
- probes-errors.mjs: missing-field
返されたメッセージ field messages is required - HTTP 400
invalid_request_errorステータスコードが実際の原因と異なる- 実際に起きていること
- そのエンドポイントは本サイトにありません。/v1/embeddings、/v1/completions、/v1/images/generations はすべてこのケースになります。しかもボディは messages が必須だと述べるため、本当の原因とはまったく無関係な方向を指します。
- 対処方法
- 本サイトが提供するのは chat completions と Anthropic の messages エンドポイントです。フレームワークが内部で embeddings を呼んでいる場合、その部分は別のプロバイダーが必要です。
- SDK の再試行
- しない(即座に失敗)
- 実際のエンドポイントで計測
- probes-errors.mjs: unsupported-endpoint
返されたメッセージ `messages` is required and must be a non-empty array. - HTTP 400
空文字列- 実際に起きていること
- リクエストボディが正しい JSON ではありません。上流が自身の "Invalid request:" という接頭辞を二重に付けますが、これは表示上の問題です。
- 対処方法
- 手書きのペイロードかシェルのクォートが原因のことが多いです。送信前に JSON を検証し、シェルではボディ全体をシングルクォートで囲んでください。
- SDK の再試行
- しない(即座に失敗)
- 実際のエンドポイントで計測
- probes-errors.mjs: malformed-json
返されたメッセージ Invalid request: Invalid request: invalid JSON request body
静かな失敗
エラーより厄介な HTTP 200
200を返し、例外も投げず、プログラムがそのまま進んでしまう失敗が 3 つあります。おかしいのは内容か請求額です。だからこそ自力では見つけにくいのです。
画像は受け取られ、そして無視される
上流は 5 つのモデルに image_ratio を付けています。あれは課金係数であって、視覚能力を意味しません。5 つとも data URL の画像を受け取り 200を返し、見ていない画像について自信たっぷりに答えます——プローブが送ったのは純緑色の PNG ですが、色を当てたモデルは 1 つもありませんでした。推奨モデルはむしろ 400で拒否します。2 つの失敗のうち、そちらのほうが安全です。
クライアント互換性マトリクスより
max_completion_tokens はテキストを抑えるが、請求は抑えない
上限を 12にしても moonshotai/kimi-k2.5の課金は 261、21.8 倍でした。切り詰め自体は効いています(finish_reason=length)。超過分は推論トークンで、課金されるのに content には現れません。この上限から算出したコスト見積もりは、同じ倍率で過小になります。
クライアント互換性マトリクスより
Anthropic のメッセージ id に msg_ 接頭辞がない
POST /v1/messages は接頭辞なしの 16 進数 id を返します。msg_ 接頭辞を前提にアサートしたり、id を解析してレスポンスを振り分けるコードは一致しません——ボディのそれ以外は仕様どおりであるにもかかわらず。
クライアント互換性マトリクスより
パース
エラーボディの形
外側は必ず {"error": {...}} ですが、フィールドの集合は一定ではありません。param があるエラーとないエラーがあり、code は空文字列であることが多いです。すべてのフィールドを省略可能として扱ってください。
{"error":{"code":"","message":"Invalid token (request id: 2026090114474514374…)","type":"new_api_error"}}{"error":{"message":"Invalid URL (POST /v1/fine_tuning/jobs)","type":"invalid_request_error","param":"","code":""}}どのメッセージも末尾に request id が付き、リクエストごとに異なります。このページと見比べる前に取り除いてください。逆に、問題を報告するときは必ず添えてください——ログでそのリクエストを特定できる唯一の手がかりです。
切り分け
ほぼ何でも切り分けられる 3 ステップ
この順番で。1 つずつ層を除外していくので、手が止まったところが答えです。
まずキーと経路を確認する
GET /v1/models はクレジットを消費せず、同じキーを使います。200とモデル一覧が返れば、キー・ネットワーク・CDN エッジのすべてに問題がないことが分かります。つまり原因は認証ではなくリクエストボディです。
curl -s https://api.y-api.bestvirtualgoods.com/v1/models -H "Authorization: Bearer $YAPI_KEY" | head -c 200curl で再現する
これで SDK を切り離せます。curl が成功して自分のコードが失敗するなら、差はそのライブラリのリクエストの組み立て方にあり、本サイト側ではありません。
curl -i https://api.y-api.bestvirtualgoods.com/v1/chat/completions \ -H "Authorization: Bearer $YAPI_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'切り分け中は再試行を切る
再試行を切れば、自分のリクエストが原因の 500や 503が 1 回目で表に出ます。2 回の無駄な待ちが挟まりません。終わったら戻してください——本物の一時障害に対しては再試行に意味があります。
client = OpenAI( base_url="https://api.y-api.bestvirtualgoods.com/v1", api_key=os.environ["YAPI_KEY"], max_retries=0, # 切り分け時のみ )
どれにも当てはまらない場合
ステータスページでは本サイト自体が劣化しているかどうかを、過去 30 日分の記録とともに確認できます。そこが緑のままで解決しないときは、エラーボディの request id を送っていただくのが最も有効です。