ガイド一覧へ戻る
トラブルシューティング·2026年7月17日·読了6分

OpenAI互換APIが401/403を返す — base_urlとヘッダーの落とし穴

OpenAI互換APIの目的はSDKがそのまま動くことです。したがって401が発生する場合、ほとんどの場合バグは変更した2行、つまりbase_urlとapi_keyにあります。ここでは、実際に発生する順に失敗パターンを説明します。

最終確認日:。

OpenAI互換APIの目的はSDKがそのまま動くことです。したがって401が発生する場合、ほとんどの場合バグは変更した2行、つまりbase_urlとapi_keyにあります。ここでは、実際に発生する順に失敗パターンを説明します。

エラー

response (HTTP 401)
{
  "error": {
    "type": "invalid_api_key",
    "message": "Invalid or missing API key.",
    "code": "invalid_api_key"
  }
}

原因と対処法の概要

原因対処法
base_urlに/v1サフィックスがない(または二重になっている)ほとんどのゲートウェイでは、ベースURLを正確にhttps://host/v1にする必要があります。SDK自身が/chat/completionsを追加します。
別のホストで発行されたキーsk-…キーは発行元のサービスに対してのみ認証できます。プレフィックスとホストの対応を確認してください。
企業プロキシ / WAFがAuthorizationヘッダーを削除しているクリーンなネットワークからテストし、Authorizationを通過させるようプロキシを設定してください。
OPENAI_API_KEY環境変数が明示的なキーを上書きしているSDKはデフォルトで環境変数を読み取ります。一部の構成では古い環境変数が黙って優先されます。api_keyを明示的に渡してください。

SDKがアクセスしている正確なURLを確認する

client.base_urlを出力し、GET /v1/modelsを呼び出してください。これは最も低コストな認証済みエンドポイントです。/modelsが機能するなら認証は正常で、エラーは別の場所にあります:

check.py
from openai import OpenAI

client = OpenAI(
    base_url="https://api.kunavo.com/v1",   # exactly one /v1
    api_key="sk-kn-...",                 # explicit beats env vars
)
print(client.base_url)
print([m.id for m in client.models.list().data][:5])

同じホストをCurlしてSDKを切り分ける

Authorization: Bearer付きのcurlが機能し、SDKが機能しない場合は、SDKの実際のリクエストを比較してください(OPENAI_LOG=debugを設定)。10回に9回はプロキシまたは環境変数が何かを書き換えています。

Kunavo経由で呼び出している場合

Kunavoのエンドポイントはhttps://api.kunavo.com/v1にあり、OpenAIのAPI形式に厳密に準拠し、Bearer認証を使用します。GET /v1/modelsは認証のスモークテストとして機能します。コードがapi.openai.comに対して動作しているなら、base_urlをKunavoに向けることだけが変更点です。同じSDK、同じワイヤ形式で、1つのキーでClaude、GPT、メディアモデルを利用できます。

よくある質問

ゲートウェイの401と403 — 違いは?

401 = 認証情報自体が受け付けられなかった(キーがない、または無効)。403 = キーは有効だが、その操作が許可されていない(無効化されたキー、停止されたアカウント、許可されていないモデル)。エラー本文を読んでください。互換APIでは理由がerror.messageに入っています。

ローカルでは動くのにCIで401になるのはなぜ?

CIは別の環境です。シークレットが設定されていない、別のサービス用に設定されている、またはプロキシがヘッダーを削除している可能性があります。CI内部からrepr(key[:12])とbase_urlをログ出力し、実際に送信されている内容を確認してください。

関連ガイド

エラーの詳しい意味はエラーリファレンスをご覧ください。キーは新規登録と認証ガイドから1分で取得できます。