hiyouga/LlamaFactory · error · ValueError

Empty formatter should not contain any placeholder.

Error message

Empty formatter should not contain any placeholder.

What it means

EmptyFormatter is meant to be a constant slot list (e.g. an empty user prompt or a fixed eos token). Its __post_init__ scans string slots for the {{placeholder}} regex and raises ValueError if any is found — placeholders make no sense in a formatter whose apply() ignores kwargs and returns slots verbatim.

Source

Thrown at src/llamafactory/data/formatter.py:53

    def extract(self, content: str) -> str | list["FunctionCall"]:
        r"""Extract a list of tuples from the response message if using tools.

        Each tuple consists of function name and function arguments.
        """
        raise NotImplementedError


@dataclass
class EmptyFormatter(Formatter):
    def __post_init__(self):
        has_placeholder = False
        for slot in filter(lambda s: isinstance(s, str), self.slots):
            if re.search(r"\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}", slot):
                has_placeholder = True

        if has_placeholder:
            raise ValueError("Empty formatter should not contain any placeholder.")

    @override
    def apply(self, **kwargs) -> SLOTS:
        return self.slots


@dataclass
class StringFormatter(Formatter):
    def __post_init__(self):
        has_placeholder = False
        for slot in filter(lambda s: isinstance(s, str), self.slots):
            if re.search(r"\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}", slot):
                has_placeholder = True

        if not has_placeholder:
            raise ValueError("A placeholder is required in the string formatter.")

    @override

View on GitHub (pinned to f28afaf635)

Solutions

  1. Remove the {{...}} placeholder from the EmptyFormatter slots, or
  2. Switch to StringFormatter (or a subclass) if the slot genuinely needs substitution.

Example fix

# before
EmptyFormatter(slots=["Answer: {{response}}"])

# after
StringFormatter(slots=["Answer: {{response}}"])
Defensive patterns

Strategy: validation

Validate before calling

import re
ph = any(re.search(r"\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}", s) for s in slots if isinstance(s, str))
if ph:
    assert formatter_cls is not EmptyFormatter, "EmptyFormatter cannot hold placeholders — use StringFormatter"

Prevention

When it happens

Trigger: Defining a custom template whose element uses EmptyFormatter but the slot text contains something like {{query}} or {{system}}; usually a copy-paste from a StringFormatter-based template where the placeholder was left behind.

Common situations: Writing/registering a custom template and mistaking which formatter class to use; refactoring a template and switching StringFormatter to EmptyFormatter without removing the placeholder.

Related errors


AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14). Data as JSON: /api/errors/42a3d41bf8f6c5c9. Report an issue: GitHub.