{"record":{"id":"da081c3d9ec074d6","repo":"hiyouga/LlamaFactory","slug":"expected-a-string-got-value","errorCode":null,"errorMessage":"Expected a string, got {value}","messagePattern":"Expected a string, got (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/data/formatter.py","lineNumber":78,"sourceCode":"@dataclass\nclass StringFormatter(Formatter):\n    def __post_init__(self):\n        has_placeholder = False\n        for slot in filter(lambda s: isinstance(s, str), self.slots):\n            if re.search(r\"\\{\\{[a-zA-Z_][a-zA-Z0-9_]*\\}\\}\", slot):\n                has_placeholder = True\n\n        if not has_placeholder:\n            raise ValueError(\"A placeholder is required in the string formatter.\")\n\n    @override\n    def apply(self, **kwargs) -> SLOTS:\n        elements = []\n        for slot in self.slots:\n            if isinstance(slot, str):\n                for name, value in kwargs.items():\n                    if not isinstance(value, str):\n                        raise RuntimeError(f\"Expected a string, got {value}\")\n\n                    slot = slot.replace(\"{{\" + name + \"}}\", value, 1)\n                elements.append(slot)\n            elif isinstance(slot, (dict, set)):\n                elements.append(slot)\n            else:\n                raise RuntimeError(f\"Input must be string, set[str] or dict[str, str], got {type(slot)}.\")\n\n        return elements\n\n\n@dataclass\nclass FunctionFormatter(StringFormatter):\n    def __post_init__(self):\n        super().__post_init__()\n        self.tool_utils = get_tool_utils(self.tool_format)\n\n    @override","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/data/formatter.py#L60-L96","documentation":"Inside StringFormatter.apply, for each string slot every kwarg value is substituted; a value that is not a Python str raises RuntimeError. apply receives fields extracted from the dataset example (query, response, system, content, ...), so a non-string column value — None (missing field), int/float, list, or dict — triggers this.","triggerScenarios":"Formatting a dataset whose examples lack a field used by the template (None substituted); columns stored as lists (e.g. multi-turn content arrays fed to a single-turn template); numeric labels in a column mapped to a placeholder.","commonSituations":"Dataset schema drift: field renamed (output -> response) so lookups return None; sharegpt conversations lists passed to alpaca formatting; JSON datasets where a value parses as number instead of string.","solutions":["Inspect the failing example: the message prints the offending value, which identifies the missing/mistyped column.","Fix dataset_info.json column mapping (e.g. output column name) so every placeholder resolves to a string field.","Normalize the dataset: cast columns to str, fill missing fields with \"\", and ensure single-turn templates get scalar strings not lists.","If a field can legitimately be absent, preprocess to empty string before training."],"exampleFix":"# before: dataset rows have null \"output\" for some examples\n# StringFormatter \"{{query}} -> {{response}}\" receives response=None\n\n# after: clean the dataset first\nds = ds.map(lambda x: {\"output\": x[\"output\"] or \"\"})  # and map output->response in dataset_info","handlingStrategy":"validation","validationCode":"# validate dataset fields against template placeholders before training\nPLACEHOLDERS = {\"query\", \"response\", \"system\", \"content\", \"tools\"}\nfor ex in itertools.islice(dataset, 100):\n    for k in PLACEHOLDERS & set(ex):\n        assert ex[k] is None or isinstance(ex[k], str), f\"column {k} must be str or None, got {type(ex[k])}\"","typeGuard":"def is_str_or_none(v) -> bool:\n    return v is None or isinstance(v, str)","tryCatchPattern":"try:\n    encoded = template.encode(example)\nexcept RuntimeError as e:\n    if \"Expected a string\" in str(e):\n        logger.error(\"non-string column in example %s — fix column mapping\", example)\n        raise","preventionTips":["Map dataset column names correctly in dataset_info.json (e.g. output->response).","Preprocess: fill nulls with \"\" and cast columns to string.","Ensure single-turn templates receive scalar strings, not conversation lists."],"tags":["formatter","dataset","data-quality","template"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}