unsloth/unsloth
Andrew Chen b307823b1d
fix(chat_templates): bind loop_messages when default_system_message is None (#7199)
* fix(chat_templates): bind loop_messages when default_system_message is None

construct_chat_template(default_system_message=None) built a system part that
binds loop_messages only inside the `{% if messages[0]['role'] == 'system' %}`
arm. The `Fix missing loop_messages` step right below then found no
unconditional `{% set loop_messages = messages %}`, concluded loop_messages was
missing, and rewrote `{% for message in loop_messages %}` back to
`{% for message in messages %}` -- undoing the `messages[1:]` skip.

A caller-supplied system message therefore reached the loop and tripped
raise_exception:

    Only user and assistant roles are supported!

Add the `{% else %}` arm so loop_messages is always bound, mirroring the
default_system_message is not None branch minus the default text. That also
stops the rewrite from firing, since the unconditional binding is now present.

Renders before / after, same template, same inputs:

    default_system_message  input        before                       after
    None                    system msg   raise_exception              'Be terse.\n### User: Hi\n'
    None                    no system    '### User: Hi\n'             unchanged
    'You are helpful.'      system msg   'Be terse.\n### User: Hi\n'  unchanged
    'You are helpful.'      no system    'You are helpful.\n...'      unchanged

The rewrite still fires for templates with no {SYSTEM} part, which is what it
was there for -- verified unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Scope loop_messages binding to {SYSTEM} templates for PR #7199

The None branch now only adds the else arm when system_part contains
{SYSTEM}, so a static prefix with no {SYSTEM} placeholder keeps raising on a
caller system message instead of silently dropping it. Strengthen the tests:
assert the default does not leak when a caller system message is present, and
add a regression test for the static prefix case.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: danielhanchen <danielhanchen@gmail.com>
2026-07-19 06:33:48 -07:00
..
dataprep fix(dataprep): skip .jsonl lines that are valid JSON but not objects (#7195) 2026-07-18 05:54:50 -07:00
kernels Propagate fp8 block_size before the early return in get_lora_parameters_bias (#7189) 2026-07-17 16:30:45 -07:00
models Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
optimizers Reduce and tighten code comments and docstrings repo-wide (#6095) 2026-06-08 23:09:51 -07:00
registry fix(registry): don't register deepseek models at import time (#7227) 2026-07-19 03:37:23 -07:00
utils Probe xformers support on sm_120 instead of disabling it by version (#6828) 2026-07-14 00:01:25 -03:00
__init__.py fix(mlx): relax context-store timeout by default (#7141) 2026-07-17 17:13:19 -03:00
_auto_install.py Upgrade setuptools and wheel in the auto-install command (#6282) 2026-06-13 03:59:15 -07:00
_compressed_quantize.py Fix export-time trust_remote_code bypass in FP8/INT8/GGUF-LoRA export (#6869) 2026-07-05 05:16:39 -07:00
_gpu_init.py Silence torch._check_is_size FutureWarning and shim it if torch removes it (#7023) 2026-07-09 02:26:36 -07:00
chat_templates.py fix(chat_templates): bind loop_messages when default_system_message is None (#7199) 2026-07-19 06:33:48 -07:00
device_type.py Reduce and tighten code comments and docstrings repo-wide (#6095) 2026-06-08 23:09:51 -07:00
import_fixes.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
ollama_template_mappers.py Re-apply #4939: updated models template mappers (#4950) 2026-04-15 07:52:12 -07:00
save.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
tokenizer_utils.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
trainer.py Reset torch.compile cache poisoned by a stray forward before trainer.train() (#6511) 2026-06-22 05:39:48 -07:00