{"record":{"id":"21374722396cffa9","repo":"hiyouga/LlamaFactory","slug":"dict-is-not-supported","errorCode":null,"errorMessage":"Dict is not supported.","messagePattern":"Dict is not supported\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/data/template.py","lineNumber":241,"sourceCode":"    def _convert_slots_to_jinja(slots: \"SLOTS\", tokenizer: \"PreTrainedTokenizer\", placeholder: str = \"content\") -> str:\n        r\"\"\"Convert slots to jinja template.\"\"\"\n        slot_items = []\n        for slot in slots:\n            if isinstance(slot, str):\n                slot_pieces = slot.split(\"{{content}}\")\n                if slot_pieces[0]:\n                    slot_items.append(\"'\" + Template._jinja_escape(slot_pieces[0]) + \"'\")\n                if len(slot_pieces) > 1:\n                    slot_items.append(placeholder)\n                    if slot_pieces[1]:\n                        slot_items.append(\"'\" + Template._jinja_escape(slot_pieces[1]) + \"'\")\n            elif isinstance(slot, set):  # do not use {{ eos_token }} since it may be replaced\n                if \"bos_token\" in slot and tokenizer.bos_token_id is not None:\n                    slot_items.append(\"'\" + tokenizer.bos_token + \"'\")\n                elif \"eos_token\" in slot and tokenizer.eos_token_id is not None:\n                    slot_items.append(\"'\" + tokenizer.eos_token + \"'\")\n            elif isinstance(slot, dict):\n                raise ValueError(\"Dict is not supported.\")\n\n        return \" + \".join(slot_items)\n\n    def _get_jinja_template(self, tokenizer: \"PreTrainedTokenizer\") -> str:\n        r\"\"\"Return the jinja template.\"\"\"\n        prefix = self._convert_slots_to_jinja(self.format_prefix.apply(), tokenizer)\n        system = self._convert_slots_to_jinja(self.format_system.apply(), tokenizer, placeholder=\"system_message\")\n        user = self._convert_slots_to_jinja(self.format_user.apply(), tokenizer)\n        assistant = self._convert_slots_to_jinja(self.format_assistant.apply(), tokenizer)\n        jinja_template = \"\"\n        if prefix:\n            jinja_template += \"{{ \" + prefix + \" }}\"\n\n        if self.default_system:\n            jinja_template += \"{% set system_message = '\" + self._jinja_escape(self.default_system) + \"' %}\"\n\n        jinja_template += (\n            \"{% if messages[0]['role'] == 'system' %}{% set loop_messages = messages[1:] %}\"","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/data/template.py#L223-L259","documentation":"When exporting a chat template to Jinja2 format (_convert_slots_to_jinja, used by get_template_and_fix_tokenizer / saving chat templates), slot elements of dict type cannot be represented because Jinja conversion only understands strings, {{placeholder}} slots, and set-type bos/eos tokens. Encountering a {'token': ...} dict slot raises ValueError('Dict is not supported.').","triggerScenarios":"Calling template._get_jinja_template(tokenizer) (or an export/API path that materializes the Jinja chat template) on a template whose formatter slots contain a {\"token\": ...} entry, such as templates that reference tokens by name rather than via the eos_token set.","commonSituations":"Registering a custom template with {\"token\": \"<|sep|>\"} slots and then serving it via the OpenAI-style API or exporting the chat template; version upgrades that started building Jinja templates for API serving.","solutions":["Replace dict slots with plain string literals of the exact token text (e.g. \"<|sep|>\") so the Jinja template embeds it verbatim.","Or use the set form {\"eos_token\"}/{\"bos_token\"} which the converter translates to the tokenizer's special tokens.","Avoid paths that materialize the Jinja template for the custom template, or patch _convert_slots_to_jinja to handle dict tokens."],"exampleFix":"# before\nformat_user=StringFormatter(slots=[\"<user>{{content}}\", {\"token\": \"<|sep|>\"}])\n\n# after\nformat_user=StringFormatter(slots=[\"<user>{{content}}<|sep|>\"])","handlingStrategy":"validation","validationCode":"def template_jinja_exportable(template) -> bool:\n    for fmt in (template.format_user, template.format_assistant, template.format_prefix, template.format_system):\n        if any(isinstance(s, dict) for s in (fmt.slots or [])):\n            return False\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid {'token': ...} slots if you plan to serve/export via Jinja chat templates; prefer literal strings or the eos/bos set form.","Test template export with template._get_jinja_template(tokenizer) once after registration."],"tags":["template","jinja","export"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}