冒頭まとめ
OpenAI API の 403 は、公式のエラー一覧では1項目しか定義されていません。国・地域・領域が対応外である、というものです。
このエラーには、他と違う特徴があります。応答の type が invalid_request_error ではなく request_forbidden になります。code は unsupported_country_region_territory です。この2語が見えた時点で、系統が確定します。
そして最も重要な点です。判定されているのは利用者の所在地ではなく、要求の送信元 IP アドレスがどこと判定されたかです。対応国にいても、経路の途中で別の地域と判定されれば 403 になります。実際、提供元の窓口も利用者に対し、IP アドレスを教えてほしい、正しくない地域に判定されていないか確認する、と応じています。
もう1つ、プログラムから呼んだ場合の 403 として、資源へのアクセス権が無い場合があります。公式のソフトウェア開発キットでは、要求した資源へのアクセス権が無い状態として定義され、正しいキー・組織 ID・資源 ID を使っているか確認するよう案内されています。
逆に、403 だと思われがちだが違うものがあります。残高や利用額の上限は 429、モデルへのアクセス権は 404、キーの失効や組織の不一致は 401 です。いずれも 403 では返りません。
エラーの概要
地域の非対応は、次の形で返ります。
{
"error": {
"code": "unsupported_country_region_territory",
"message": "Country, region, or territory not supported",
"param": null,
"type": "request_forbidden"
}
}
他のエラーと並べると違いが際立ちます。400 や 401 の type は invalid_request_error ですが、こちらは request_forbidden です。type を見るだけで、内容の問題でも認証の問題でもないと分かります。
もう1つ確認すべきことがあります。応答が JSON かどうかです。上の形が返っていれば、API の層が判断した結果です。JSON ではなく HTML の遮断画面が返っている場合、判断したのは API の層ではなく、その手前にある仕組みです。調べる先が変わるため、本文の形式を最初に確認してください。
まず最初に:type と送信元 IP を確認する
第一に、type を読みます。request_forbidden であれば地域の系統です。
第二に、応答が JSON かどうかを見ます。HTML であれば、API より手前の層で遮断されています。
第三に、要求が実際にどの IP から出ているかを確認します。手元の所在地ではなく、プログラムが動いている環境の外向き IP です。
第四に、その IP がどの地域と判定されるかを確認します。ここが自分の認識とずれていれば、原因はそこです。
よくある原因と解決手順
原因1:送信元 IP が対応外の地域と判定されている
最も多い形です。特徴的なのは、手元では通るのに配備先で失敗するという現れ方をすることです。キーも要求の内容も同じなので、原因の特定が遅れます。
疑うべきなのは、要求が自分の手を離れてから外へ出るまでの経路です。クラウド上の実行環境、中継のプロキシ、配信網の実行環境、社内から外部へ出る回線。このどれかの出口 IP が判定の対象になります。
# プログラムが動く環境の外向き IP を確認する
curl -sS https://api.ipify.org
# その環境から最小の要求を投げ、type を確認する
curl -sS https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" \
| python3 -c "import json,sys; e=json.load(sys.stdin).get('error',{}); print(e.get('type'), '|', e.get('code'))"
対応地域で運用しているつもりでも、経路の途中で別の地域を通っていれば判定はそちらに従います。まず経路を把握することが先決です。
原因2:地理判定そのものが誤っている
対応国から呼んでいるのに 403 が返る場合です。利用者側の設定ではなく、IP アドレスの地域判定が実態と合っていないことがあります。
新しく割り当てられたアドレス帯や、クラウド事業者が特定の地域で使い始めた範囲では、判定に使われる情報が追いついていない場合があります。
この場合、プログラム側をいくら直しても解決しません。取れる手段は2つです。
# 1. 別の実行環境(別リージョンなど)から到達するかを確認する
# 通るなら、元の環境の出口 IP に問題が絞られる
# 2. 出口 IP を控えて、提供元の窓口に確認を依頼する
curl -sS https://api.ipify.org
後述の実例でも、提供元の窓口が利用者に IP アドレスの共有を求め、最終的に提供元側で修正されています。利用者側で対処しきれない種類があると知っておくと、無駄な試行錯誤を避けられます。
原因3:資源へのアクセス権が無い
開発キットの区分で PermissionDeniedError として現れる場合です。公式の説明は、要求した資源へのアクセス権が無い、というもので、対処として正しいキー・組織 ID・資源 ID を使っているかの確認が挙げられています。
地域の系統と違い、type は request_forbidden にはなりません。資源を特定する識別子が要求に含まれている場合(アシスタント、ファイル、微調整済みモデルなど)に起こります。
その資源が、いま使っているキーの属するプロジェクトのものかを確認してください。組織やプロジェクトをまたいで識別子を使い回すと、この形になります。
原因4:403 ではないものを 403 として調べている
下記はいずれも 403 ではありません。この4つを 403 の原因として探すと、必ず行き止まりになります。
残高が尽きた、あるいは支出や利用額の上限に達した場合は 429 です。公式のエラー一覧では、残高切れ、組織の支出上限、プロジェクトの支出上限、承認された利用上限が、それぞれ独立した識別子として 429 の側に定義されています。
指定したモデルが存在しない、またはアクセス権が無い場合は 404 で、code は model_not_found です。
キーが失効している、組織やプロジェクトと一致しない、エンドポイントに必要な権限が無い場合は 401 です(OpenAI API の 401 の記事)。IP の許可リストとの不一致も、地域の判定とは別に 401 の側で定義されています。
送った内容そのものに問題がある場合は 400 です。
原因5:応答が API の層から来ていない
type も code も無く、HTML の遮断画面が返っている場合です。この場合、API の層には到達していません。
判断したのは、経路上の防御の仕組みです。表示される内容と識別子は、その仕組みが定義したものであり、本記事の内容は当てはまりません。まず「誰が返したか」を確定させてから調べる先を決める、という順序は他のエラーと同じです。
補足:似ているが別のもの
認証の失敗は 401 です。公式では 401 の原因が4種類に整理されており、そのうちの1つが IP の許可リストとの不一致です。同じ IP に関する話でも、許可リストは 401、地域の判定は 403、と分かれています。
上限や請求に関するエラーは 429 です。公式には、請求関連では error.code を見て具体的な原因を特定するよう書かれています。
他の基盤では、403 が担う範囲がまったく違います。GCP では権限の不足が 403 の中心で、応答に不足している権限の名前が入ります(GCP の 403 の記事)。Azure でも同様に権限やネットワークの制御が中心です(Azure の 403 の記事)。OpenAI API の 403 を他の基盤の感覚で読むと、原因を取り違えます。
切り分けの順序
typeを読む。request_forbiddenなら地域の系統。- 応答が JSON かを確認する。HTML なら API の層に届いていない。
codeがunsupported_country_region_territoryかを確認する。- プログラムが動く環境の外向き IP を確認する。手元の所在地ではない。
- 別の実行環境から到達するかを試す。通るなら出口 IP に原因が絞られる。
- 対応地域から呼んでいるのに失敗するなら、判定の誤りを疑い、IP を控えて窓口に確認を依頼する。
- 資源の識別子を含む要求なら、その資源が現在のプロジェクトのものかを確認する。
- 残高・モデル・キーの話であれば、そもそも 403 ではない。429・404・401 を見る。
確認コマンド集
# 1. 状態コードと本文の形式を同時に確認する(JSON か HTML か)
curl -sS -i https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" | head -20
# 2. type と code だけを取り出す
curl -sS https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" \
| python3 -c "import json,sys; e=json.load(sys.stdin).get('error',{}); print(e.get('type'), '|', e.get('code'))"
# 3. 実行環境の外向き IP を確認する
curl -sS https://api.ipify.org; echo
# 4. コンテナや実行環境の中から確認する(配備先で実行)
docker run --rm curlimages/curl -sS https://api.ipify.org; echo
# 5. 経路を確認する(中継が挟まっていないか)
env | grep -iE 'http_proxy|https_proxy|no_proxy'
# 6. 開発キットの例外種別を確認する
python3 -c "
from openai import OpenAI
import openai
try:
OpenAI().models.list()
except openai.PermissionDeniedError as e:
print('PermissionDenied:', e.status_code, e.body)
except openai.AuthenticationError as e:
print('Authentication:', e.status_code, e.body)
"
Editor’s Note
このエラーの判定が「利用者の国」ではなく「送信元 IP の判定結果」であることを、当事者のやり取りごと記録した相談があります(Cloud Run in asia-northeast3 Suddenly Getting ‘unsupported_country_region_territory’ Error)。
2025年6月、韓国の実行環境に配備していたサービスが、突然 403 を返し始めました。相談者はこう書いています。コードも配備の設定も変えていない。キーは有効で、上限にも達していない。そして「この地域は対応しているはずだ」と。
同じ症状の報告が次々と続きます。同じクラウドの同じ地域を使う利用者が、数日のうちに4人以上集まりました。
3日後、提供元の窓口が返答します。韓国は対応国であると認めたうえで、使用している IP アドレスを共有してほしい、誤って対象外の地域に判定されていないか確認する、という内容でした。この一文が、判定の実体を明かしています。見られているのは所在地の申告ではなく、通信の出どころです。
ある利用者は待ちきれず、実行環境の地域を別の場所へ変えることで解決しています。設定を1つも直さず、出口を変えただけです。そして6日後、窓口から修正済みの連絡があり、報告者たちの環境は元のまま復旧しました。
この記録から得られる教訓は2つあります。1つは、403 に当たったとき最初に確認すべきなのが、プログラムではなく要求がどこから出ているかだということ。もう1つは、利用者側では直しようがない場合があるということです。手を尽くしても変わらないなら、出口の IP を控えて提供元に伝えるのが、最短の道になります。
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。
この記事でエラーは解決しましたか?