hiyouga/LlamaFactory · error · ValueError
Input must be string, set[str] or dict[str, str], got {type(
Error message
Input must be string, set[str] or dict[str, str], got {type(elem)} What it means
Template slot encoding only accepts three element types: plain strings (encoded), dicts with a 'token' key (converted via convert_tokens_to_ids), and sets containing 'bos_token'/'eos_token' (mapped to the tokenizer's special-token ids). Any other type in a formatter's slots list raises this error. It fires inside Template._convert_elements_to_ids while encoding messages.
Source
Thrown at src/llamafactory/data/template.py:128
r"""Get the token ids of thought words."""
return tokenizer.encode(self.add_thought(), add_special_tokens=False)
def _convert_elements_to_ids(self, tokenizer: "PreTrainedTokenizer", elements: "SLOTS") -> list[int]:
r"""Convert elements to token ids."""
token_ids = []
for elem in elements:
if isinstance(elem, str):
if len(elem) != 0:
token_ids += tokenizer.encode(elem, add_special_tokens=False)
elif isinstance(elem, dict):
token_ids += [tokenizer.convert_tokens_to_ids(elem.get("token"))]
elif isinstance(elem, set):
if "bos_token" in elem and tokenizer.bos_token_id is not None:
token_ids += [tokenizer.bos_token_id]
elif "eos_token" in elem and tokenizer.eos_token_id is not None:
token_ids += [tokenizer.eos_token_id]
else:
raise ValueError(f"Input must be string, set[str] or dict[str, str], got {type(elem)}")
return token_ids
def _encode(
self,
tokenizer: "PreTrainedTokenizer",
messages: list[dict[str, str]],
system: Optional[str],
tools: Optional[str],
) -> list[list[int]]:
r"""Encode formatted inputs to pairs of token ids.
Turn 0: prefix + system + query resp
Turn t: query resp.
"""
system = system or self.default_system
encoded_messages = []
for i, message in enumerate(messages):View on GitHub (pinned to f28afaf635)
Solutions
- Change any non-string slot to a supported form: use a string literal for text, {"token": "<your_token>"} for a token lookup, or {"eos_token"}/{"bos_token"} (set literal) for special tokens.
- Inspect your register_template call and print each formatter's .slots to find the offending element type shown in the message.
- If you need a raw token id, wrap it as a token string that the tokenizer knows (ensure it exists in the vocab) and use the dict form.
Example fix
# before
register_template(
name="custom",
format_user=StringFormatter(slots=["<user>", 123, "{{content}}<eos>"]),
)
# after
register_template(
name="custom",
format_user=StringFormatter(slots=["<user>{{content}}", {"token": "<eos>"}]),
) Defensive patterns
Strategy: type-guard
Validate before calling
from llamafactory.data.template import SLOTS
def slots_are_valid(slots) -> bool:
for s in slots:
if not isinstance(s, (str, set, dict)):
return False
if isinstance(s, set) and not s <= {"bos_token", "eos_token"}:
return False
if isinstance(s, dict) and "token" not in s:
return False
return True Type guard
def is_valid_slot(elem) -> bool:
"""True if elem is accepted by Template._convert_elements_to_ids."""
if isinstance(elem, str):
return True
if isinstance(elem, set):
return elem <= {"bos_token", "eos_token"}
if isinstance(elem, dict):
return "token" in elem
return False Prevention
- Only use str, {'token': ...} dicts, and {'eos_token'}/{'bos_token'} sets in formatter slots.
- Unit-test custom templates by encoding one toy conversation before starting a training run.
When it happens
Trigger: Registering a custom template via register_template whose formatter slots contain an int, None, list, or a dict missing the 'token' key (e.g. slots=["<user>", 123, "{{content}}"]); passing malformed slot data when constructing StringFormatter/EmptyFormatter; subclassing Template and returning non-slot types from a custom formatter's apply().
Common situations: Writing a custom template for a new model family and putting a raw integer token id or None in slots instead of {"token": "..."}; copy-pasting template definitions between LlamaFactory versions where the slot schema changed; passing a dict like {"text": "..."} instead of the expected {"token": "..."}.
Related errors
- Empty formatter should not contain any placeholder.
- A placeholder is required in the string formatter.
- Unexpected role: {}
- Stop words are required to replace the EOS token.
- Template {name} already exists.
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/e18e0ad0378f5caf.
Report an issue: GitHub.