冒頭まとめ
OpenAI API の 400 Bad Request は、送った要求の内容が受け付けられなかったことを示します。公式の説明では、要求の形式が壊れているか、必須のパラメータが欠けている場合とされ、エラー文言がどこが問題かを教えてくれるはずだと書かれています。
実際、応答には機械が読める形で場所と種類が入ります。param に問題のあるパラメータの名前、code に種類の識別子です。この2つを読めば、直す場所と直し方がほぼ決まります。
よく見る code は3つです。unsupported_parameter は、そのパラメータ自体がそのモデルでは使えない、という意味です。unsupported_value は、パラメータは使えるがその値が使えない、という意味です。context_length_exceeded は、入力と出力の合計が上限を超えた場合です。
もう1つ、境界として押さえておくべき点があります。モデル名の誤りは 400 ではありません。存在しないモデルや権限の無いモデルを指定した場合、返るのは 404 で、code は model_not_found です。400 の原因としてモデル名を探し始めると遠回りになります。
エラーの概要
最も多く見る形は、使えないパラメータを送った場合です。
{
"error": {
"message": "Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead.",
"type": "invalid_request_error",
"param": "max_tokens",
"code": "unsupported_parameter"
}
}
param に max_tokens と名指しされ、message には代わりに使うべき名前まで書かれています。推測の余地がありません。
値だけが問題の場合は、code が変わります。
{
"error": {
"message": "Unsupported value: 'temperature' does not support 0.7 with this model. Only the default (1) value is supported.",
"type": "invalid_request_error",
"param": "temperature",
"code": "unsupported_value"
}
}
上限超過の場合は、内訳まで示されます。
{
"error": {
"message": "This model's maximum context length is 4097 tokens. However, you requested 4927 tokens (3927 in the messages, 1000 in the completion). Please reduce the length of the messages or completion.",
"type": "invalid_request_error",
"param": "messages",
"code": "context_length_exceeded"
}
}
プログラムから呼んでいる場合、公式のソフトウェア開発キットでは BadRequestError として現れます。以前は別の名前でしたが、対応する状態コードは同じ 400 です。
まず最初に:param と code を読む
第一に、param を読みます。問題のあるパラメータがそのまま入っています。
第二に、code を読みます。unsupported_parameter ならパラメータを外すか置き換える、unsupported_value なら値だけを直す、context_length_exceeded なら量を減らす、と対処が分かれます。
第三に、message を最後まで読みます。置き換え先の名前や、許される値、トークンの内訳など、必要な情報が書かれていることが多くあります。
第四に、code が model_not_found であれば、それは 400 ではなく 404 です。調べる対象が変わります。
よくある原因と解決手順
原因1:そのモデルで使えないパラメータを送っている
現在最も多い形です。推論系のモデルでは、従来の max_tokens が使えず max_completion_tokens を使います。公式の資料でも max_tokens は非推奨とされ、これらのモデルとは互換性が無いと明記されています。
Before(従来のまま呼ぶ):
client.chat.completions.create(
model="o3-mini",
messages=[{"role": "user", "content": "hi"}],
max_tokens=500, # → unsupported_parameter
)
After(モデルに応じて名前を変える):
client.chat.completions.create(
model="o3-mini",
messages=[{"role": "user", "content": "hi"}],
max_completion_tokens=500,
)
複数のモデルを切り替えて使う場合、送るパラメータ自体をモデルごとに変える必要があります。同じ呼び出しコードを使い回す設計だと、モデルを増やした瞬間に破綻します。
この形は周辺の道具でも大量に起きています。道具の設定画面でパラメータを空にしても、道具側が既定値を送り続けてエラーが消えない、という報告もあります。自分で外したつもりでも、実際に送られているかどうかは別問題です。
原因2:パラメータは使えるが、値が使えない
code が unsupported_value の場合です。名前は受け付けられるので、パラメータを消す必要はありません。
推論系のモデルで temperature に既定値以外を指定した場合が代表例です。文言に「既定の1のみ対応」と明記されるため、対処はその値に合わせるか、指定自体をやめることです。
# 値を既定に合わせる、または指定しない
client.chat.completions.create(model="o3-mini", messages=[...])
この2つの区別は実務で効きます。unsupported_parameter は送ってはいけない、unsupported_value は送ってよいが値が違う。前者に対して値だけ変えても直りません。
原因3:入力と出力の合計が上限を超えている
code が context_length_exceeded の場合です。ここで見落とされやすいのは、上限に数えられるのは入力だけではないという点です。
前掲の文言を読むと、要求した合計と、その内訳(messages 側と completion 側)が示されています。つまり、出力の上限として指定した値も合計に含まれます。入力が短いのに超過する場合、原因は出力側の指定であることがあります。
対処は3つです。入力を短くする、出力の上限指定を小さくする、あるいは文脈の広いモデルへ切り替える。会話履歴を積み上げる作りでは、履歴の打ち切りを実装しないと使うほど確実に到達します。
# 履歴を直近だけに絞る(例:直近10件)
messages = [system_message] + history[-10:]
原因4:構造そのものが不正
param が messages で、文言が構造に触れている場合です。必須の項目が欠けている、役割の指定が不正、内容が空、といった形が該当します。
公式にも、API リファレンスで対象のメソッドを確認し、パラメータの名前・型・値・形式が仕様と一致しているかを見直すよう案内されています。あわせて、データの符号化や形式、大きさが適切かを確認するよう書かれています。
送っている内容そのものを確認するのが確実です。手元で組み立てた辞書を印字するのではなく、実際に送られる本文を見てください。
原因5:モデル名の誤りを 400 として探している
対処ではなく、探し方の問題です。冒頭で述べたとおり、存在しないモデルや権限の無いモデルの指定は 404 で返ります。code は model_not_found、文言は対象が存在しないか権限が無い、という趣旨になります。
400 が返っているなら、モデル名は少なくとも解決できています。モデル名の綴りを何度も見直すのは、この場合まったくの遠回りです。逆に 404 が返っているなら、パラメータをいくら調整しても通りません。
補足:似ているが別のもの
内容の形式は正しいのに処理できない場合は 422 です。公式の説明では、形式が正しいにもかかわらず処理できなかった状態とされ、もう一度試すよう案内されています。400 とは違い、再試行が対処になり得る点が特徴です。
認証の失敗は 401 です。キーの誤りだけでなく、組織やプロジェクトの不一致、権限、IP の許可リストも含まれます(OpenAI API の 401 の記事)。
上限や請求に関するエラーは 429 です。トークンの話が出てくるため 400 の上限超過と混同されやすいのですが、context_length_exceeded は1回の要求の大きさ、429 は一定時間あたりの量や残高の問題です。
Azure 経由で同じモデルを使う場合も、パラメータの仕様は同じ系統のエラーを返します。ただし配備名やバージョンの指定が加わるため、確認すべき項目が増えます(Azure の 400 の記事)。
切り分けの順序
paramを読む。問題のパラメータがそこに名指しされている。codeを読む。unsupported_parameterは外す、unsupported_valueは値を直す。messageを最後まで読む。置き換え先の名前や許される値が書かれている。codeがmodel_not_foundなら 404。400 として調べない。- 上限超過なら、内訳を見る。出力側の指定が原因のこともある。
- 道具を経由しているなら、実際に送られている本文を確認する。外したつもりでも送られていることがある。
- モデルを切り替えて使うなら、パラメータの組み立てもモデルごとに分ける。
- 形式が正しいのに通らないなら、422 の可能性を確認する。こちらは再試行が対処になり得る。
確認コマンド集
# 1. param と code だけを取り出す(最重要)
curl -sS https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d @request.json \
| python3 -c "import json,sys; e=json.load(sys.stdin).get('error',{}); print('param:', e.get('param'), '| code:', e.get('code')); print(e.get('message'))"
# 2. 実際に送られる本文を確認する(道具を疑う場合)
python3 -c "
import json
body = {'model':'o3-mini','messages':[{'role':'user','content':'hi'}],'max_tokens':500}
print(json.dumps(body, ensure_ascii=False, indent=2))
"
# 3. 開発キットの例外から中身を取り出す
python3 -c "
from openai import OpenAI
import openai
try:
OpenAI().chat.completions.create(model='o3-mini',
messages=[{'role':'user','content':'hi'}], max_tokens=10)
except openai.BadRequestError as e:
print(e.status_code, e.body)
"
# 4. モデル名が有効かを先に確かめる(404 との切り分け)
curl -sS -o /dev/null -w "%{http_code}\n" https://api.openai.com/v1/models/o3-mini \
-H "Authorization: Bearer $OPENAI_API_KEY"
# 5. 利用できるモデルの一覧を取得する
curl -sS https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" \
| python3 -c "import json,sys; [print(m['id']) for m in json.load(sys.stdin)['data']]" | sort | head -20
Editor’s Note
param が示すのは「仕様上おかしいパラメータ」ではありません。**実際に送られたパラメータ**です。この違いが効く場面があります。
家庭向け自動化基盤の統合機能で報告された不具合が、それを示しています(OpenAI Conversation o1/o3 models fail with ‘max_tokens’ is not supported with this model)。2025年1月、推論系のモデルを選ぶと max_tokens が使えない旨の 400 で失敗する、という内容です。
注目すべきは続きです。報告者は設定画面で該当の項目を空にしてみたものの、それは既定値の150を設定したことになるだけで、エラーは消えなかったと書いています。利用者から見れば「外した」のに、送信される要求には値が入り続けていたわけです。
param に max_tokens と出ている以上、それは送られています。画面上の見え方ではなく、応答が事実を示している。この読み方ができれば、設定を疑うのではなく、送信部分を疑う段階へ一足飛びに進めます。
同じエラーは、公式の開発キットのリポジトリにも「ライブラリの不具合」として報告されています(openai.BadRequestError: Error code: 400)。実際にはライブラリの問題ではなく、モデル側の仕様変更に呼び出し側が追随していない状態でした。400 は、送った側と受け取る側の食い違いを指しています。どちらが古いのかを見極めるのが、このエラーの本質です。
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。
この記事でエラーは解決しましたか?