{"record":{"id":"3eeb3a68e9175c45","repo":"hiyouga/LlamaFactory","slug":"fewer-tag-tags-than-provided-media-files-unuse","errorCode":null,"errorMessage":"Fewer {tag} tags than provided media files ({unused} unused).","messagePattern":"Fewer (.+?) tags than provided media files \\((.+?) unused\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/v1/plugins/data_plugins/converter.py","lineNumber":123,"sourceCode":"    for segment in _TAG_PATTERN.split(text):\n        block_type = _TAG_TO_BLOCK.get(segment)\n        if block_type is not None:\n            try:\n                path = next(media_iters[segment])\n            except StopIteration:\n                raise ValueError(f\"More {segment} tags than provided media files.\") from None\n            blocks.append({\"type\": block_type, \"value\": path})\n        elif segment:\n            blocks.append({\"type\": \"text\", \"value\": segment})\n    return blocks\n\n\ndef _assert_media_consumed(media_iters: dict[str, Any]) -> None:\n    \"\"\"Ensure every media file was referenced by a tag (fewer tags than media -> error).\"\"\"\n    for tag, media_iter in media_iters.items():\n        unused = len(list(media_iter))\n        if unused:\n            raise ValueError(f\"Fewer {tag} tags than provided media files ({unused} unused).\")\n\n\nclass DataConverterPlugin(BasePlugin):\n    \"\"\"Plugin for data converters.\"\"\"\n\n    def __call__(self, raw_sample: dict[str, Any]) -> Sample:\n        return super().__call__(raw_sample)\n\n\n@DataConverterPlugin(\"alpaca\").register()\ndef alpaca_converter(raw_sample: AlpacaSample) -> SFTSample:\n    \"\"\"Convert Alpaca sample to SFT sample.\n\n    See raw example at: https://huggingface.co/datasets/llamafactory/alpaca_gpt4_en\n\n    Args:\n        raw_sample (AlpacaSample): Alpaca sample.\n","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/v1/plugins/data_plugins/converter.py#L105-L141","documentation":"The mirror check of error 343: after converting a sample, the converter asserts every provided media file was consumed by a placeholder tag. If the images/videos/audios list is longer than the number of corresponding tags in the text, the unused count is reported and conversion fails.","triggerScenarios":"A dataset row with more entries in 'images'/'videos'/'audios' than the corresponding placeholder tags appearing in the concatenated conversation text.","commonSituations":"Datasets ported from other formats where the media array keeps extra files; deleting a tag from the prompt but not the media list; single-tag conventions (one <image> tag, multiple images) applied to v1, which requires exact 1:1 correspondence.","solutions":["Make tag counts and media list lengths match exactly per sample per modality.","Add the missing placeholder tags into the text (e.g. one <image> per image).","Trim extra unused entries from the media arrays.","Write a pre-flight validator that fails fast on the whole file before training starts."],"exampleFix":"// before\n{\"instruction\": \"Describe this\", \"images\": [\"a.jpg\", \"b.jpg\"]}\n\n// after\n{\"instruction\": \"Describe <image> and <image>\", \"images\": [\"a.jpg\", \"b.jpg\"]}","handlingStrategy":"validation","validationCode":"def counts_match(row) -> bool:\n    text = ' '.join(str(row.get(k, '')) for k in ('instruction', 'input', 'output', 'conversations'))\n    for col, tag in TAGS.items():\n        media = row.get(col) or []\n        media = media if isinstance(media, list) else [media]\n        if len(re.findall(re.escape(tag), text)) != len(media):\n            return False\n    return True","typeGuard":"def counts_match(row: dict) -> bool:\n    \"\"\"Exact 1:1 media tag <-> media file correspondence for all modalities.\"\"\"\n    ...","tryCatchPattern":"try:\n    converter(raw)\nexcept ValueError as e:\n    if 'Fewer' in str(e):\n        row.setdefault('images', [])[:] = row['images'][:used]  # or log & drop row\n    raise","preventionTips":["Use exact equality checks (not just >=) when validating multimodal rows.","Prefer generating text tags from media lists in preprocessing scripts.","Fail the whole dataset check in CI, not at training time row-by-row."],"tags":["data","multimodal","dataset-conversion","validation"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}