Il tuo array messages termina con un turno dell'assistente e i modelli Claude 4.6 e successivi lo interpretano come un prefill e lo rifiutano. Termina la conversazione con un messaggio dell'utente, quindi sposta ciò che faceva il prefill — forzare il JSON, saltare un preambolo, mantenere una persona, riprendere una risposta interrotta — nella sostituzione documentata da Anthropic.
L’errore
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "This model does not support assistant message prefill. The conversation must end with a user message."
},
"request_id": "req_..."
}Cause e soluzioni in breve
| Causa | Soluzione |
|---|---|
| L'ultima voce in messages ha role: "assistant" | È un prefill e i modelli Claude 4.6 e successivi lo rifiutano. Termina con un messaggio dell'utente. |
| Un framework ha lasciato per ultimo un messaggio vuoto dell'assistente | Rimuovi il messaggio finale dell'assistente senza contenuto prima dell'invio. |
| Hai precompilato “{” per forzare il JSON | Usa gli output strutturati (output_config.format). |
| Hai usato il prefill per saltare un preambolo, mantenere una persona o riprendere una risposta interrotta | Un'istruzione nel prompt di sistema, un ruolo nel prompt di sistema o una continuazione nel turno dell'utente. |
| Un gestore della memoria, un ciclo dell'agente o un passaggio di consegne ha lasciato per ultimo un turno dell'assistente | Normalizza la coda una sola volta, subito prima della richiesta, invece di farlo in ogni percorso del codice. |
Quali modelli Claude rifiutano il prefill (a settembre 2026)
Il riferimento agli errori di Anthropic è chiaro: i modelli Claude 4.6 e successivi non supportano il prefill dell'ultimo messaggio dell'assistente e una richiesta che lo utilizza restituisce esattamente questo 400 (https://platform.claude.com/docs/en/api/errors#prefill-not-supported). Nello specifico, si tratta di Claude Opus 4.6 e di ogni Opus successivo, incluso Claude Opus 5.5 (https://platform.claude.com/docs/en/models/opus-5-5/migration-guide); Claude Sonnet 4.6 e Claude Sonnet 5 (https://platform.claude.com/docs/en/models/sonnet-5/migration-guide); e Claude Fable 5 e Fable 5.1 (https://platform.claude.com/docs/en/models/fable-5-1/migration-guide). Claude Haiku 4.5 accetta ancora il prefill, così come Claude Sonnet 4.5 e Claude Opus 4.5 — per questo l'errore tende a comparire insieme a una modifica dell'ID del modello anziché a una modifica del codice. I messaggi dell'assistente precedenti nella conversazione, inclusi gli esempi few-shot, non sono interessati.
Termina con un turno dell'utente — inclusa la correzione in una riga
Spesso nessuno ha scritto intenzionalmente un prefill: qualcosa nello stack ha lasciato per ultimo un messaggio dell'assistente. Le segnalazioni pubbliche lo attribuiscono a un gestore della memoria che ne aggiunge uno (issue #1694 di Strands), a un ciclo dell'agente che ripete la richiesta dopo un turno erroneamente considerato incompleto (issue #46415 di opencode), a risposte consecutive e passaggi di consegne tra agenti (issue #4907 di LiveKit) e a un messaggio vuoto dell'assistente lasciato alla fine (PR #7931 di AutoGen). Se il messaggio finale è vuoto, rimuovilo: questa è la riga necessaria. Se contiene testo che vuoi continuare, segui le indicazioni di migrazione di Anthropic per le continuazioni: inserisci la continuazione in un messaggio dell'utente che citi il punto in cui la risposta si è interrotta. Un'eccezione documentata da lasciare invariata: un pause_turn degli strumenti server, come la ricerca web, viene continuato reinviando invariato il contenuto dell'assistente in pausa (https://platform.claude.com/docs/en/agents-and-tools/tool-use/server-tools).
from openai import OpenAI
client = OpenAI(base_url="https://api.kunavo.com/v1", api_key="sk-kn-...")
def end_on_user(messages: list[dict]) -> list[dict]:
"""Claude 4.6 and later reject a conversation whose last turn is the assistant's."""
last = messages[-1] if messages else None
if not last or last["role"] != "assistant" or last.get("tool_calls"):
return messages # tool_calls are owed tool results instead
content = last.get("content")
if not content or (isinstance(content, str) and not content.strip()):
return messages[:-1] # the one line: drop an empty tail
tail = content[-200:] if isinstance(content, str) else "..."
return messages + [{
"role": "user",
"content": f"Your previous response was interrupted and ended with {tail!r}. "
"Continue from where you left off.",
}]
messages = [
{"role": "user", "content": "Explain HTTP caching in three bullets."},
{"role": "assistant", "content": ""}, # the empty tail a framework left behind
]
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=end_on_user(messages),
)
print(resp.choices[0].message.content)Sostituisci ciò che faceva il prefill
La guida al prompting di Anthropic associa ogni vecchio uso del prefill a una sostituzione (https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices#migrating-away-from-prefilled-responses). Forzare il JSON: output strutturati, che vincolano la risposta al tuo schema e sono disponibili su Claude Haiku 4.5, Sonnet 4.5, Opus 4.5 e su ogni modello successivo (https://platform.claude.com/docs/en/build-with-claude/structured-outputs); per YAML o un altro formato, la guida consiglia di richiedere la struttura e riprovare quando non viene rispettata. Classificazione: uno strumento con un enum delle etichette valide oppure output strutturati. Saltare un preambolo: un'istruzione nel prompt di sistema come “Rispondi direttamente senza preambolo.” Mantenere una persona: imposta il ruolo nel prompt di sistema (https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices#give-claude-a-role) e inserisci promemoria periodici nel turno dell'utente invece di un messaggio dell'assistente precompilato. Una risposta interrotta: la continuazione nel turno dell'utente descritta sopra. Forzare una chiamata allo strumento non è una sostituzione immediata ovunque: Claude Fable 5.1 e Claude Opus 5.5 rifiutano tool_choice any e tool con un proprio 400 (https://platform.claude.com/docs/en/api/errors#forced-tool-use-not-supported).
# Before: messages ended with {"role": "assistant", "content": "{"}
# Kunavo forwards output_config as sent; the reply is constrained to the schema.
curl https://api.kunavo.com/v1/messages \
-H "x-api-key: sk-kn-..." \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Extract the name and email: John Smith <john@example.com>"}
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"}
},
"required": ["name", "email"],
"additionalProperties": false
}
}
}
}'Se chiami tramite Kunavo
Kunavo inoltra un turno finale dell'assistente; non lo corregge. /v1/messages passa l'array messages al servizio upstream senza modificarlo e, su /v1/chat/completions, il traduttore trasferisce un messaggio finale con role: "assistant" come turno finale dell'assistente nella richiesta Claude — incluso uno vuoto, quindi rimuovi tu quelli vuoti. Anthropic rifiuta un turno finale precompilato su ogni modello claude-* che serviamo, eccetto claude-haiku-4-5, e quel 400 ti arriva con il testo del messaggio intatto, seguito dall'ID della richiesta upstream: in formato Anthropic su /v1/messages, con invalid_request_error come tipo, come nell'API Anthropic (fino al 24 settembre 2026 era api_error), e in formato OpenAI su /v1/chat/completions (type upstream_error, code upstream_400). Un 400 non viene mai ritentato su un altro canale e la chiamata fallita viene registrata a costo zero. Per il JSON, invia uno schema invece di un prefill: /v1/messages inoltra output_config così come lo hai inviato e, su /v1/chat/completions, un response_format di tipo json_schema viene tradotto in output_config.format. Il 2026-09-24 quel campo vincolava la risposta allo schema su ogni modello claude-* che serviamo. Un response_format json_object non ha un equivalente Claude e non viene applicato, mentre uno schema inviato insieme a un turno finale precompilato produce un 400 autonomo, incluso claude-haiku-4-5: "When using output format, pre-filling the `assistant` response is not supported." L'endpoint nativo e la struttura della richiesta che inoltra sono documentati in documentazione dell'API Messages.
Domande frequenti
Quali modelli Claude non supportano il prefill del messaggio dell'assistente?
Secondo la documentazione di Anthropic a settembre 2026, ogni modello Claude dalla versione 4.6 in poi: Claude Opus 4.6 e ogni Opus successivo, Claude Sonnet 4.6 e Sonnet 5, Claude Fable 5 e 5.1 e i modelli Mythos. Claude Haiku 4.5, Sonnet 4.5 e Opus 4.5 ne accettano ancora uno.
Come posso forzare l'output JSON da Claude senza prefill?
Usa gli output strutturati: passa uno schema JSON in output_config.format e la risposta sarà vincolata a esso. Attraverso un endpoint compatibile con OpenAI, invialo come response_format con type json_schema; Kunavo lo traduce in output_config.format. Anthropic indica che il prefill dei messaggi è incompatibile con gli output JSON in ogni caso.
Perché ricevo questo errore se non ho mai usato un prefill?
Qualcosa nel tuo stack ha lasciato per ultimo un messaggio dell'assistente: un gestore della memoria o della sessione, un ciclo dell'agente che ripete la richiesta dopo un turno, un passaggio di consegne tra agenti o un messaggio vuoto dell'assistente che nessuno ha rimosso. Registra l'array messages esattamente come viene inviato: il suo ultimo elemento avrà role: "assistant".
Posso comunque includere messaggi dell'assistente nella conversazione?
Sì. Solo il turno finale è soggetto alla restrizione; i messaggi dell'assistente precedenti, inclusi gli esempi few-shot, non sono interessati.
Perché succede anche attraverso un endpoint compatibile con OpenAI?
Perché il gateway trasferisce il tuo messaggio finale con role: "assistant" come turno finale dell'assistente Claude: lo stesso prefill, con una forma diversa. Il traduttore chat di Kunavo fa esattamente questo e lo stesso messaggio è stato segnalato attraverso altri gateway compatibili con OpenAI (issue #13768 di opencode). La correzione è la stessa: termina con un messaggio dell'utente.
Guide correlate
- API Claude 400 «tool_use ids were found without tool_result blocks» — la regola dell'ordine
- “`temperature` e `top_p` non possono essere specificati entrambi per questo modello” — inviane uno solo e, sui modelli Claude più recenti, nessuno dei due
- “Unsupported parameter: 'max_tokens' is not supported with this model” — usa max_completion_tokens
- API Claude — guida completa per chiamare Claude su Kunavo
Ulteriori dettagli sul significato degli errori sono disponibili in riferimento agli errori; ottenere una chiave richiede un minuto tramite registrazione e la guida all’autenticazione.