hiyouga/LlamaFactory · error · ValueError
More {segment} tags than provided media files.
Error message
More {segment} tags than provided media files. What it means
During multimodal sample conversion, each inline media placeholder tag (e.g. <image>, <video>, <audio>) in the text consumes one path from the sample's media column. This ValueError fires when the text contains more placeholder tags of a modality than the sample provides media files for that modality, so a tag has no path to bind.
Source
Thrown at src/llamafactory/v1/plugins/data_plugins/converter.py:111
def _to_content_blocks(text: str, media_iters: dict[str, Any]) -> list[Content]:
"""Split ``text`` on inline media placeholders, interleaving media-url content blocks.
Each placeholder consumes the next path from its modality iterator (in document order). Plain
text with no placeholders yields a single text block (byte-identical to the legacy behavior).
Raises on an unmatched placeholder (more tags than media files).
"""
if not _TAG_PATTERN.search(text):
return [{"type": "text", "value": text}]
blocks: list[Content] = []
for segment in _TAG_PATTERN.split(text):
block_type = _TAG_TO_BLOCK.get(segment)
if block_type is not None:
try:
path = next(media_iters[segment])
except StopIteration:
raise ValueError(f"More {segment} tags than provided media files.") from None
blocks.append({"type": block_type, "value": path})
elif segment:
blocks.append({"type": "text", "value": segment})
return blocks
def _assert_media_consumed(media_iters: dict[str, Any]) -> None:
"""Ensure every media file was referenced by a tag (fewer tags than media -> error)."""
for tag, media_iter in media_iters.items():
unused = len(list(media_iter))
if unused:
raise ValueError(f"Fewer {tag} tags than provided media files ({unused} unused).")
class DataConverterPlugin(BasePlugin):
"""Plugin for data converters."""
def __call__(self, raw_sample: dict[str, Any]) -> Sample:View on GitHub (pinned to f28afaf635)
Solutions
- Fix the offending rows: make the number of media tags in the text exactly equal the length of the corresponding images/videos/audios list.
- Audit the dataset with a small script counting tags vs list lengths per sample to find bad rows.
- Remove stray placeholder tags from text if the media was never intended.
- If a single sample uses one media file repeated, duplicate the path in the media list.
Example fix
// before
{"instruction": "Describe <image> and <image>", "output": "...", "images": ["a.jpg"]}
// after
{"instruction": "Describe <image> and <image>", "output": "...", "images": ["a.jpg", "b.jpg"]} Defensive patterns
Strategy: validation
Validate before calling
import json, re
from llamafactory.extras.constants import IMAGE_PLACEHOLDER, VIDEO_PLACEHOLDER, AUDIO_PLACEHOLDER
TAGS = {'images': IMAGE_PLACEHOLDER, 'videos': VIDEO_PLACEHOLDER, 'audios': AUDIO_PLACEHOLDER}
def sample_ok(row) -> bool:
text = ' '.join(str(row.get(k, '')) for k in ('instruction', 'input', 'output', 'conversations'))
for col, tag in TAGS.items():
media = row.get(col) or []
media = media if isinstance(media, list) else [media]
if len(re.findall(re.escape(tag), text)) > len(media):
return False
return True
assert all(sample_ok(json.loads(l)) for l in open('train.jsonl')) Type guard
def has_matching_tag_counts(row: dict) -> bool:
"""True when every media tag in text has a corresponding media file."""
return sample_ok(row) Try / catch
try:
sample = converter(raw)
except ValueError as e:
if 'tags than provided media' in str(e):
logger.error('bad row skipped: %s', raw.get('id', '?'))
continue
raise Prevention
- Run a tag-count vs media-list-length validator over JSONL before training.
- Generate placeholder tags programmatically from the media list instead of editing text by hand.
- Add a dataset CI check for multimodal datasets.
When it happens
Trigger: A dataset row whose instruction/output text contains N '<image>' tags but whose 'images' field has fewer than N entries (same for videos/audios). Raised from _to_content_blocks during DataConverterPlugin conversion (alpaca/sharegpt converters).
Common situations: Hand-edited JSONL where an image tag was added but the images array not updated; templates that inject an extra media placeholder; OCR/caption datasets with inconsistent tag counts per row.
Related errors
- Fewer {tag} tags than provided media files ({unused} unused)
- Invalid input type {input_item.type}.
- Unknown dataset filetype: {filetype}.
- DPO training dataset is empty: {dataset_path}
- DPO training requires pair-format samples containing chosen/
AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14).
Data as JSON: /api/errors/43b13e8b08678e86.
Report an issue: GitHub.