Claude assistant prefill 400 エラー:非対応モデルと代替手段
Claude Opus・Sonnet 4.6 以降と Fable 5 系は assistant で終わるリクエストを 400 で拒否します。代替は prefill の用途次第です。
目次

This model does not support assistant message prefill. The conversation must end with a user message. は、messages 配列の最後が role: "assistant" になっているリクエストを、それを受け付けないモデルに送ったときに返る 400 invalid_request_error です。拒否するのは Claude Opus 4.6 以降(Opus 5.5 まで)、Sonnet 4.6 以降(Sonnet 5.5 まで)、Fable 5 と Fable 5.1、Claude Mythos Preview で、Sonnet 4.5、Haiku 4.5 とそれ以前のモデルはまだ受け付けます。再送やパラメータの調整では直りません。最後の assistant メッセージをなくし、それが担っていた役目を別の仕組みに移すのが修正です。
何に移すかは、その assistant メッセージで何をしていたかで決まります。JSON の書き出しを固定していたなら output_config.format(structured outputs)、前置きを省かせていたならシステムプロンプト、途中で切れた回答の続きを書かせていたなら部分回答を含む user メッセージです。自分のコードではなく GitHub Copilot や opencode などのツールで出ている場合は、ツールの更新、モデルの切り替え、新しい会話での再開、開発元への報告が利用者側でできることです。
モデルの対応状況とリクエストの形は、2026年10月5日時点の Anthropic 公式ドキュメント(API エラー一覧、structured outputs、各モデルの移行ガイド)に基づきます。コードはドキュメントのリクエスト形に沿った例で、実行結果を示すものではありません。
エラーの意味:messages の最後が assistant だと 400 になる
assistant メッセージのプリフィル(prefill)とは、リクエストの最後に role: "assistant" のメッセージを置き、Claude の回答の書き出しをこちらで決めておく使い方です。たとえば最後に { を置いて JSON から書き始めさせる、analysis のような XML の開始タグを置いて決まった形式で書かせる、といった用途で広く使われてきました。
Claude 4.6 以降のモデルはこの形を受け付けません。API が返すエラー本文は次のとおりです。
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "This model does not support assistant message prefill. The conversation must end with a user message."
}
}エラーになるのは、次のようなリクエストです。
{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "次のレビューを positive・negative・neutral のどれかに分類し、JSON で返してください:配送は早かったが箱が潰れていた"},
{"role": "assistant", "content": "{\"label\": \""}
]
}最後の assistant を取り除き、会話が user メッセージで終わるようにすればこのエラーは出なくなります。ただし、取り除いただけでは書き出しの固定がなくなるので、出力が JSON にならない、前置きが付く、といった別の問題が起きます。そこを下の「代替手段」で埋めます。
ゲートウェイやツールを通すと、同じ英文が別のエラーに包まれて届きます。LiteLLM では litellm.BadRequestError: AnthropicException - ...、GitHub Copilot 経由では invalid_request_body というコード付き、OpenRouter では表示が Provider returned error だけになり、ログを開くと上流の Anthropic がこの英文を返している、という報告があります。Databricks の Foundation Model APIs(FMAPI)では HTTP 400 BAD_REQUEST の中に同じ英文が入ります。表示が違っても、本文に assistant message prefill があれば同じ原因です。
prefill を拒否するモデル:Opus・Sonnet 4.6 以降と Fable 5 系
API エラー一覧には「Claude 4.6 以降のモデルと Claude Mythos Preview は assistant メッセージの prefill をサポートしない」とあり、各モデルの移行ガイドが個別に同じことを書いています。
| モデル | 最後が assistant のリクエスト | 根拠 |
|---|---|---|
| Claude Opus 4.6、4.7、4.8、Opus 5、Opus 5.5 | 400 で拒否 | Opus 5.5 移行ガイド:Opus 4.6 以降の Opus は Opus 5.5 を含めて 400 |
| Claude Sonnet 4.6、Sonnet 5、Sonnet 5.5 | 400 で拒否 | Sonnet 5.5 移行ガイド |
| Claude Fable 5、Fable 5.1 | 400 で拒否 | Fable 5.1 移行ガイド:Fable 5 から変更なし |
| Claude Mythos Preview | 400 で拒否 | API エラー一覧 |
| Claude Sonnet 4.5、Haiku 4.5、Opus 4.5 以前 | 受け付ける | Sonnet 5.5 移行ガイド、Opus 5.5 移行ガイド |
表は2026年10月5日時点の Anthropic 公式ドキュメントに基づきます。表にない新しいモデルも、「4.6 以降」の記述に当てはまる限り拒否側と考えてください。
Sonnet 4.5 や Haiku 4.5 に戻せばエラーは消えますが、これは時間稼ぎです。どのモデルがいつまで提供されるかは変わるので、戻す前にモデル一覧で提供状況を確かめ、並行して prefill をなくす作業を進めるほうが確実です。Opus 4.6 から 4.7 以降へ上げるときは、prefill のほかにもリクエストの決まりが変わります(Claude Opus 4.7 vs Claude Opus 4.6:2026年、いまアップグレードすべきか)。
prefill の代替手段は「何のための prefill だったか」で決まる
prefill は一つの仕組みで複数の目的を兼ねていたので、代替も目的ごとに分かれます。Sonnet 5.5 移行ガイドは置き換え先を次のように整理しています。
| prefill でしていたこと | 典型的な prefill | 置き換え先 |
|---|---|---|
| 出力形式を固定する | {、[、XML の開始タグ(result など) | structured outputs(output_config.format)。分類なら enum 付きの strict ツール(tool_choice は auto) |
| 前置きをなくす | 答え: | システムプロンプトで「前置きなしで答える」と指示する |
| 不要な拒否を避ける | 回答の書き出しを先に書いておく | user メッセージで明確に指示する。多くはこれで足りる |
| 中断した回答の続きを書かせる | 途中までの回答 | 部分回答を user メッセージに入れて続きを頼む |
| 文脈を念押しする | 「前提を踏まえて回答します」など | 念押しを user ターンに書く |

JSON で返させていた場合:output_config.format か strict tool use
{ の prefill で JSON を始めさせていたコードは、structured outputs に置き換えるのが本命です。JSON Schema を output_config.format に渡すと、回答はスキーマに沿った JSON として text ブロックで返ります。prefill と違って、閉じ忘れや必須フィールドの欠落も起きません。ドキュメントのリクエスト形は次のとおりです。
curl https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "次のレビューを分類してください:配送は早かったが箱が潰れていた"}
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"label": {"type": "string", "enum": ["positive", "negative", "neutral"]},
"reason": {"type": "string"}
},
"required": ["label", "reason"],
"additionalProperties": false
}
}
}
}'SDK を使うなら、client.messages.parse() がスキーマの変換と応答の検証をまとめて引き受けます。Python では Pydantic モデルを渡し、検証済みの結果を response.parsed_output から受け取ります。
from typing import Literal
import anthropic
from pydantic import BaseModel
class Review(BaseModel):
label: Literal["positive", "negative", "neutral"]
reason: str
client = anthropic.Anthropic()
response = client.messages.parse(
model="claude-opus-5-5",
max_tokens=1024,
messages=[
{"role": "user", "content": "次のレビューを分類してください:配送は早かったが箱が潰れていた"}
],
output_format=Review,
)
print(response.parsed_output)TypeScript では Zod のスキーマを @anthropic-ai/sdk/helpers/zod の zodOutputFormat() で包み、output_config.format に渡します。Zod オブジェクトをそのまま渡す書き方や、response.parsed で読む書き方はドキュメントの形と違います。
import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
const Review = z.object({
label: z.enum(["positive", "negative", "neutral"]),
reason: z.string(),
});
const client = new Anthropic();
const response = await client.messages.parse({
model: "claude-opus-5-5",
max_tokens: 1024,
messages: [
{ role: "user", content: "次のレビューを分類してください:配送は早かったが箱が潰れていた" },
],
output_config: { format: zodOutputFormat(Review) },
});
console.log(response.parsed_output);置き換えるときの注意は四つあります。
- API のパラメータ名は
output_config.format:以前のベータ版のoutput_formatは非推奨で、ベータヘッダーstructured-outputs-2025-11-13を付けないと 400 になります。上の Python 例のoutput_format=Reviewはparse()の引数で、SDK が送信時にoutput_config.formatへ変換します。HTTP で直接送る場合やmessages.create()ではoutput_configを使います。 - prefill と citations とは併用できない:JSON outputs は message prefilling と非互換で、citations を有効にしたまま
output_config.formatを付けると 400 になります。 parse()を使わない場合の読み取り位置:Opus 5.5 のように thinking が常に有効なモデルでは、contentの先頭が thinking ブロックになることがあります。content[0]決め打ちではなく、typeがtextのブロックを探して読みます。- 対応モデル:structured outputs の対応一覧には Fable 5.1/5、Mythos 5.1/5/Preview、Opus 5.5/5/4.8/4.7/4.6、Sonnet 5.5/5/4.6/4.5、Opus 4.5、Haiku 4.5 が並んでいます。prefill を拒否するモデルはすべて含まれます。
分類やツール呼び出しの引数を形にしたいなら、ツール定義に strict: true を付ける strict tool use も使えます。enum で選択肢を絞ったツールを用意すれば、{"label": " の prefill で選ばせていた処理を置き換えられます。JSON outputs と strict tool use は同じリクエストで併用できます。
ただし、ツール呼び出しを強制して形式を固定する方法は、新しいモデルでは prefill の代わりになりません。Opus 5.5、Sonnet 5.5、Fable 5.1 は tool_choice の {"type": "any"} と {"type": "tool", "name": "..."} を、prefill とは別の 400(tool_choice: type "tool" and "any" are not supported for this model.)で拒否し、auto と none しか受け付けません。Sonnet 5.5 移行ガイドによれば、それより前の Sonnet 5、Sonnet 4.6、Sonnet 4.5、Haiku 4.5 は強制を受け付け、Fable 5 も受け付けます。prefill をやめるついでに強制ツール呼び出しへ移すと、モデルを上げた時点でまた 400 になります。これらのモデルでは tool_choice: {"type": "auto"} にしてツールに strict: true を付けるか、JSON outputs を使います。auto ではモデルがツールを呼ばずに答えることもあるので、どんなときにツールを使うかをプロンプトで指示します。
前置きを省かせていた場合・拒否を避けていた場合:指示で置き換える
答え: のような prefill で「はい、承知しました」などの前置きを消していたなら、システムプロンプトに「前置きや確認の言葉を付けず、答えから書き始める」と書きます。回答の書き出しを先に書いて不要な拒否を避けていた場合も、Sonnet 5.5 移行ガイドは user メッセージで明確に指示すれば多くは足りるとしています。
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
system="前置き、言い換え、確認の言葉を付けず、答えの1文目から書き始めてください。",
messages=[
{"role": "user", "content": "このエラーログの原因を1文で教えてください:..."}
],
)
text = next(block.text for block in response.content if block.type == "text")
print(text)文脈の念押し(「ここまでの前提を踏まえて答えます」のような prefill)も同じで、念押しの内容を最後の user ターンに書き足します。
途中で切れた回答の続き:部分回答を user メッセージに入れる
max_tokens やストリームの中断で切れた回答を assistant メッセージとして末尾に置き、続きを書かせる方法は、prefill を拒否するモデルでは使えません。Sonnet 5.5 移行ガイドの例は「Your previous response was interrupted and ended with [previous_response]. Continue from where you left off.」で、切れた部分を user メッセージの中に入れて続きを頼む形です。日本語で書いても考え方は同じです。
def continuation_messages(history, partial, tail_chars=800):
"""history は user メッセージで終わる元の会話、partial は途中で切れた回答。"""
tail = partial[-tail_chars:]
return history + [{
"role": "user",
"content": (
"前の回答は途中で中断され、次の文で終わっています。\n"
f"<previous_response>{tail}</previous_response>\n"
"この続きから書いてください。すでに書いた部分は繰り返さないでください。"
),
}]返ってきた続きは、手元で partial の後ろにつなげます。つなぎ目で文が重なることがあるので、結合前に確認してください。
コード全体を一度に移行する:公式の移行スキル
prefill がコードのあちこちにあるなら、Opus 5.5、Sonnet 5.5、Fable 5.1 の各移行ガイドが紹介している、Claude Code 同梱の Claude API スキルが使えます。ガイドの例は Claude Code で /claude-api migrate this project to claude-opus-5-5 と実行する形で、モデル ID の置き換え、互換性のないパラメータの変更、prefill の置き換え、effort の調整を必要に応じてコードベース全体に適用し、手で確かめる項目のチェックリストを出します。編集の前に対象範囲(作業ディレクトリ全体、サブディレクトリ、ファイル指定)の確認があり、Amazon Bedrock と Claude Platform on AWS のクライアントも検出し、モデル ID の形式と機能の違いを合わせます。

Claude in Amazon Bedrock では structured outputs が使えない
Bedrock で Claude を呼んでいる場合、output_config.format が使えるかどうかは統合の種類で変わります。structured outputs のドキュメントでは、旧来の「Amazon Bedrock (Opus 4.6 and earlier)」統合では Claude Opus 4.6、Sonnet 4.6、Sonnet 4.5、Opus 4.5、Haiku 4.5 で使える一方、新しい統合の「Claude in Amazon Bedrock」では使えないとされています(2026年10月5日時点)。
Claude in Amazon Bedrock で prefill をやめる場合は、JSON の形をツール定義の入力スキーマで指定するか、システムプロンプトと user メッセージの指示で形式を伝えます。strict tool use も structured outputs の一部なので、Sonnet 5.5 移行ガイドは Bedrock 上の Sonnet 5.5 について、strict を付けずに tool_choice: {"type": "auto"} で送り、いつツールを呼ぶかをプロンプトで伝え、ツールの入力をコード側で検証する方法を示しています。Bedrock で出る 400 にはこのエラー以外にも種類があるので、エラー本文ごとの切り分けは AWS の Claude 400 エラー、メッセージ別の対処法 を参照してください。
ライブラリ経由の原因:続きの生成と空の assistant ターン
自分では prefill を書いていないのにこのエラーが出るなら、使っているライブラリが内部で assistant メッセージを末尾に足しています。公開されている修正や報告では、原因は次の二つに分かれます。
一つ目は、続きの生成やフォールバックで部分回答を assistant メッセージとして足すパターンです。 LiteLLM のルーターは、ストリームの途中で別モデルにフォールバックするとき、それまでの部分回答を assistant メッセージとして末尾に付けて再開していました。そのため Sonnet 4.6 や Opus 4.6 以降が相手だと、フォールバックのたびに 400 になり、回復できるはずのタイムアウトがチェーン全体の失敗に変わります。2026年6月11日に出た修正 PR(#30242、2026年10月5日時点で未マージ)は、sonnet-4-6 系に supports_assistant_prefill: false を設定し、prefill 非対応のモデルでは部分回答を user メッセージに載せる方式に切り替える内容です。同じ PR は livekit/agents、crewAI、agno でも同種の不具合が報告されていると挙げています。Dyad も、続きを書かせる再試行で assistant メッセージを末尾に置いていた処理を、部分回答を含む user メッセージに置き換えました(PR #3027、2026年3月23日マージ)。
二つ目は、会話履歴の末尾に空の assistant ターンが残り、新しい user 入力がないまま送ってしまうパターンです。 OpenClaw では、ハートビートやシステムイベントの後に履歴が assistant ターンで終わったまま送信される経路があり、この 400 が出ていました。修正(#69268、2026年5月1日マージ)は、新しい user 入力がなければ送信自体をしない、というものです。
自前のエージェントやチャットクライアントなら、API を呼ぶ直前に末尾を確かめる処理を一つ入れておくと、両方のパターンを防げます。
def is_empty(content):
if isinstance(content, str):
return content.strip() == ""
return all(
block.get("type") == "text" and not block.get("text", "").strip()
for block in content
)
def ready_to_send(messages):
"""末尾の空の assistant ターンを落とし、user で終わらなければ送らない。"""
msgs = list(messages)
while msgs and msgs[-1]["role"] == "assistant" and is_empty(msgs[-1]["content"]):
msgs.pop()
if not msgs or msgs[-1]["role"] != "user":
return None # 新しい user 入力がないので API を呼ばない
return msgstool_result は user ロールのメッセージで返すので、ツール実行後の会話もこのチェックを通ります。中身のある assistant メッセージで終わっている場合は、それを消すのではなく、上の「途中で切れた回答の続き」の形で user メッセージに移します。
Copilot や opencode など、コードを直せないツールで出る場合
GitHub Copilot、opencode、Google Antigravity、Databricks、LibreChat のエージェント、OpenHands などで、Claude の Opus や Sonnet を選んだときにこのエラーが出るという報告が公開されています。ツールが内部で組み立てるリクエストの末尾が assistant になっているのが原因なので、利用者が設定で直せる部分はほとんどありません。
opencode の issue #13768(「This model does not support assistant message prefill / Github Copilot with Opus 4.6」)は2026年2月15日に立ち、60日間動きがなかったため2026年9月2日に自動でクローズされましたが、2026年10月2日にも Opus 5.5 で起きるというコメントが付いています。クローズ済みの表示は解決済みを意味しません。
利用者側でできるのは次の四つです。
- ツールを最新版に更新する:会話の組み立て方が直れば、それで解消します。リリースノートで prefill や Opus・Sonnet 4.6 以降への対応を確認します。
- ツールが使うモデルを切り替える:prefill を受け付ける Sonnet 4.5 や Haiku 4.5、または Claude 以外のモデルに変えると、このエラーは出なくなります。品質や提供状況との引き換えなので、修正が出るまでのつなぎです。
- 新しい会話で始め直す:特定の会話の履歴が assistant ターンで終わった状態から抜け出せない場合は、新しい会話にすると進むことがあります。
- 開発元に報告する:使っているモデル、ツールのバージョン、エラー全文を添えて報告します。上の opencode のように既存の issue があれば、そこに状況を追記します。
ほかの 400 との見分け方:thinking ブロック、tool_result、temperature
Claude 4.6 以降に上げたときに出る 400 は、どれも invalid_request_error で、ステータスコードだけでは区別できません。決め手はメッセージ本文です。prefill のエラーは The conversation must end with a user message. で終わり、会話の終わり方だけを問題にしています。
| エラー本文の手がかり | 原因 | 直し方 |
|---|---|---|
assistant message prefill / must end with a user message | 最後のメッセージが assistant | 上の「代替手段」の節 |
thinking or redacted_thinking blocks in the latest assistant message cannot be modified | 直前の assistant メッセージの thinking ブロックを編集・並べ替え・除外して送り返した | 受け取ったブロックをそのまま返す |
"thinking.type.enabled" is not supported for this model. | Claude 4.7 以降に手動の extended thinking を指定した | adaptive thinking と output_config.effort に切り替える |
tool_choice: type "tool" and "any" are not supported for this model. | Opus 5.5、Sonnet 5.5、Fable 5.1 でツール呼び出しを強制した | auto と strict tool use、または JSON outputs に切り替える |
| tool_use に対応する tool_result がないという趣旨 | ツール呼び出しの結果を次の user メッセージで返していない | 各 tool_use に tool_result を対応させる |
temperature や top_p を含むもの | Opus 4.7 以降で既定値以外のサンプリングパラメータを送った | パラメータを削除する |
二行目の thinking ブロックのエラーも「latest assistant message」に触れますが、こちらは assistant メッセージを送ったこと自体ではなく、thinking ブロックを書き換えたことが原因です。サンプリングパラメータの 400 は Claude Opus 4.7 の temperature パラメータエラーは、数値調整ではなく削除で直す と Claude Code で top_p deprecated? まず Opus 4.7 の新しい request rule を確認 を参照してください。
表のどの 400 も、同じリクエストを再送して直ることはありません。opencode のエラー記録でもこの prefill エラーは isRetryable: false として扱われています。再試行で回復しうるサーバー側のエラーとの違いは Claude APIの500 api_error対処法:再試行後も失敗する場合の扱い を参照してください。





