hiyouga/LlamaFactory · error · ValueError
prompt is not a token-prefix of the full sequence; the chat
Error message
prompt is not a token-prefix of the full sequence; the chat template is not prefix-stable for this turn, so diff-based labeling is unsafe.
What it means
Training labels are computed by rendering the conversation without the final assistant turn (with add_generation_prompt=True) and diffing against the full render. This requires the prompt ids to be an exact token-prefix of the full ids. Some chat templates are not prefix-stable — they re-render earlier turns differently once the final turn is appended (dynamic system prompts, dates, changed enable_thinking, whitespace) or the tokenizer merges tokens across the boundary — and then diff-based labeling would mislabel tokens, so the renderer fails loudly.
Source
Thrown at src/llamafactory/v1/core/rendering/rendering.py:155
attention_mask=[1] * n,
labels=[IGNORE_INDEX] * n,
loss_weights=[0.0] * n,
)
_attach_multimodal(result)
return result
if not messages or messages[-1]["role"] != "assistant":
raise ValueError(
"training render expects the last message to be the supervised assistant turn; "
"multi-turn conversations are split per turn in process_samples."
)
prompt_ids, _ = _encode(hf_messages[:-1], messages[:-1], add_generation_prompt=True)
if input_ids[: len(prompt_ids)] != prompt_ids:
# The prompt must be a token-prefix of the full sequence for the diff to be valid. If a
# template re-renders earlier turns when the final turn is appended, fail loud rather than
# mislabel.
raise ValueError(
"prompt is not a token-prefix of the full sequence; the chat template is not "
"prefix-stable for this turn, so diff-based labeling is unsafe."
)
weight = messages[-1].get("loss_weight", 1.0)
supervised = weight > 1e-6
labels = [IGNORE_INDEX] * len(prompt_ids)
loss_weights = [0.0] * len(prompt_ids)
for tid in input_ids[len(prompt_ids) :]:
labels.append(tid if supervised else IGNORE_INDEX)
loss_weights.append(weight)
result = ModelInput(
input_ids=input_ids,
attention_mask=[1] * n,
labels=labels,
loss_weights=loss_weights,
)View on GitHub (pinned to f28afaf635)
Solutions
- Make the template deterministic and prefix-stable: remove date/time inserts and history-dependent reformatting
- Guarantee identical template kwargs for both renders (the code already forwards enable_thinking; ensure your template does not derive behavior from the presence of the last turn)
- Insert an explicit structural break before the assistant header (e.g. newline/special token the tokenizer cannot merge across)
- Test with the model's stock template; if it passes, the issue is in your custom Jinja
Example fix
# before (template fragment, not prefix-stable)
"{%- if messages[-1].role == 'assistant' %}<|old_history|>{%- endif %}"
# after (deterministic rendering of history)
"{%- for m in messages %}{{ '<|im_start|>' + m.role }}{%- endfor %}" Defensive patterns
Strategy: validation
Validate before calling
def template_is_prefix_stable(template, tokenizer, msgs) -> bool:
full = tokenizer.apply_chat_template(msgs, tokenize=True)
prompt = tokenizer.apply_chat_template(msgs[:-1], tokenize=True, add_generation_prompt=True)
return full[: len(prompt)] == prompt Prevention
- Run a prefix-stability smoke test for every new chat template before training
- Avoid date/time or last-turn-dependent constructs in custom Jinja templates
When it happens
Trigger: Using a chat template whose output for messages[:-1] is not a strict prefix of the output for messages (e.g. templates that inject the current date, reorder or trim history based on the last turn, or toggle a thinking block); tokenizers where the generation-prompt boundary merges with the preceding token (e.g. no space before the assistant header).
Common situations: Custom or third-party Jinja chat templates with time-dependent or turn-count-dependent behavior; Qwen3-style thinking templates where enable_thinking differs between the two renders; BPE tokenizers whose pretokenizer crosses the assistant-tag boundary.
Related errors
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/24ce4a41931bcbfd.
Report an issue: GitHub.