meta-llama/llama · error · AssertionError
Last message must be from user, got {dialog[-1]['role']}
Error message
Last message must be from user, got {dialog[-1]['role']} What it means
This assertion in chat_completion (llama/generation.py:354) requires the final message of every dialog to have role 'user'. The loop tokenizes prior user/assistant pairs as history and then encodes the last user message as the open-ended prompt (bos=True, eos=False) for generation; an assistant/system message in last position leaves nothing to generate from, so the library refuses it.
Source
Thrown at llama/generation.py:354
), (
"model only supports 'system', 'user' and 'assistant' roles, "
"starting with 'system', then 'user' and alternating (u/a/u/a/u...)"
)
dialog_tokens: List[int] = sum(
[
self.tokenizer.encode(
f"{B_INST} {(prompt['content']).strip()} {E_INST} {(answer['content']).strip()} ",
bos=True,
eos=True,
)
for prompt, answer in zip(
dialog[::2],
dialog[1::2],
)
],
[],
)
assert (
dialog[-1]["role"] == "user"
), f"Last message must be from user, got {dialog[-1]['role']}"
dialog_tokens += self.tokenizer.encode(
f"{B_INST} {(dialog[-1]['content']).strip()} {E_INST}",
bos=True,
eos=False,
)
prompt_tokens.append(dialog_tokens)
generation_tokens, generation_logprobs = self.generate(
prompt_tokens=prompt_tokens,
max_gen_len=max_gen_len,
temperature=temperature,
top_p=top_p,
logprobs=logprobs,
)
if logprobs:
return [View on GitHub (pinned to 689c7f261b)
Solutions
- Trim or extend the dialog so it ends with a user message: either drop a trailing assistant message or append the next user turn before calling
- If you want the model to continue an assistant reply, append an empty/short user turn like {'role':'user','content':'continue'} — this codebase has no continuation API
- Validate every dialog in the batch before submission; one bad dialog aborts the entire chat_completion call
- In UI loops, rebuild the dialog as history pairs + the fresh user question rather than replaying the raw transcript
Example fix
# before
dialog = [
{"role": "user", "content": "hello"},
{"role": "assistant", "content": "Hi! How can I help?"},
]
llama.chat_completion([dialog], max_gen_len=64) # AssertionError
# after
dialog = [
{"role": "user", "content": "hello"},
{"role": "assistant", "content": "Hi! How can I help?"},
{"role": "user", "content": "what is 2+2?"},
]
llama.chat_completion([dialog], max_gen_len=64) Defensive patterns
Strategy: validation
Validate before calling
def dialog_ends_with_user(dialog):
return bool(dialog) and dialog[-1]["role"] == "user"
assert all(dialog_ends_with_user(d) for d in dialogs), "every dialog must end with a user message" Type guard
def ends_with_user(dialog) -> bool:
return isinstance(dialog, list) and len(dialog) > 0 and dialog[-1].get("role") == "user" Try / catch
try:
result = llama.chat_completion(dialogs, max_gen_len=128)
except AssertionError as e:
if "Last message must be from user" in str(e):
dialogs = [d if d[-1]["role"] == "user" else d + [{"role": "user", "content": "continue"}] for d in dialogs]
result = llama.chat_completion(dialogs, max_gen_len=128)
else:
raise Prevention
- Keep UI dialog state ending at the user turn: append the model's reply only as history when the next question arrives
- Trim trailing assistant/system messages from imported transcripts before inference
- Validate the whole batch first — one non-conforming dialog aborts all dialogs in the chat_completion call
When it happens
Trigger: Calling llama.chat_completion(dialogs, ...) where any dialog's last element is {'role': 'assistant', ...} (or a trailing 'system'): e.g. replaying a full conversation including the model's final answer, or appending a system reminder at the end. Note it triggers even when the alternation assert (error 3) passes, e.g. [user, assistant] alone.
Common situations: - Feeding complete transcripts (which naturally end with the assistant's reply) back in for evaluation/continuation instead of trimming to end on the user turn. - Multi-turn UIs that keep the dialog list state after each generation and resubmit without appending the new user message. - Preprocessing that appends a closing system/guardrail message at the end of the conversation. - Batch pipelines where some dialogs end with 'assistant' and others with 'user', failing the whole batch.
Related errors
- model only supports 'system', 'user' and 'assistant' roles,
- Error: special tags are not allowed as part of the prompt.
- no checkpoint files found in {ckpt_dir}
- Loading a checkpoint for MP={len(checkpoints)} but world siz
AI-assisted analysis of meta-llama/llama@689c7f261b (2026-08-15).
Data as JSON: /api/errors/3090a6d8c94730a9.
Report an issue: GitHub.