Spot the bug: chat-template code that drops the EOS from the labels.
Click any words you think contain an error. Click again to unmark.
Two bugs compound. add_generation_prompt=True is the inference setting (no EOS); labels = input_ids[:-1] then drops the final token anyway. Both must be fixed for the model to learn to stop.
Picture teaching someone when to stop talking by reading them example conversations. Two things can quietly remove the stop signal from your examples. First, you accidentally read aloud only the part up to the moment someone is about to reply, never the reply ending; the listener never hears the closing cue. Second, even when you do read the closing cue, you skip the very last word of every example to save time. After enough examples like that, the listener has no model of when to wrap up. At conversation time they keep going forever. The fix is to read the complete examples, including the final closing cue, every single time.
Detailed answer & concept explanation~8 min readEverything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
4 min: identify the two errors, explain why each removes EOS from the labels, walk through the correct recipe, then describe the startup assertion that catches the bug class.
| Setting | Train (correct) | Inference (correct) | Buggy train |
|---|---|---|---|
| add_generation_prompt | False | True | True (drops EOS) |
| labels construction | input_ids.clone() + mask prompt to -100 | n/a | input_ids[:-1] (drops final token) |
| Final position in labels | EOS supervised | n/a | Token before EOS supervised; EOS gone |
| Inference behavior | Model emits EOS on turn end | Model emits EOS on turn end | Model rarely emits EOS; runs past turn |
Real products, models, and research that use this idea.
- Hugging Face apply_chat_template documentation explicitly notes that add_generation_prompt=True is for inference and warns against using it for training data.
- TRL SFTTrainer handles the chat-template rendering and labels construction correctly out of the box; the bug usually appears in custom training loops.
- Practitioners debugging runaway generation on Llama-3, Qwen, and Mistral fine-tunes regularly trace the bug to one of these two patterns in custom data-prep code.
- Open-source repos like Axolotl and Unsloth ship example chat-template recipes that explicitly avoid both bugs and serve as reference implementations.
- Production fine-tuning vendors include round-trip label verification as a startup assertion precisely because this class of bug is so easy to introduce and so silent at training time.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow would you write a startup assertion that catches both bugs before training launches?
QWhy does the bug not show up in training loss curves or eval loss curves?
Don't say thisRed flags and common mistakes that signal junior thinking. Click to expand.
Red flags and common mistakes that signal junior thinking. Click to expand.
Treating add_generation_prompt=True as the training default, or slicing labels with [:-1] to align them with logits. Both quietly remove the EOS from the supervised span and break stop behavior.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.
Same topic, related formats. Practice these next.