hiyouga/LlamaFactory · error · ValueError

The number of images does not match the number of {IMAGE_PLA

Error message

The number of images does not match the number of {IMAGE_PLACEHOLDER} tokens in {messages}.

What it means

ValueError from BasePlugin._validate_messages: the number of image files supplied for a sample does not equal the number of <image> placeholders found across the messages' content strings. The plugin counts IMAGE_PLACEHOLDER occurrences per message and compares with len(images); any mismatch aborts preprocessing of that sample.

Source

Thrown at src/llamafactory/data/mm_plugin.py:204

        if self.audio_token is not None and feature_extractor is None:
            raise ValueError("Audio feature extractor was not found, please check and update your model file.")

    def _validate_messages(
        self,
        messages: list[dict[str, str]],
        images: list["ImageInput"],
        videos: list["VideoInput"],
        audios: list["AudioInput"],
    ):
        r"""Validate if the number of images, videos and audios match the number of placeholders in messages."""
        num_image_tokens, num_video_tokens, num_audio_tokens = 0, 0, 0
        for message in messages:
            num_image_tokens += message["content"].count(IMAGE_PLACEHOLDER)
            num_video_tokens += message["content"].count(VIDEO_PLACEHOLDER)
            num_audio_tokens += message["content"].count(AUDIO_PLACEHOLDER)

        if len(images) != num_image_tokens:
            raise ValueError(
                f"The number of images does not match the number of {IMAGE_PLACEHOLDER} tokens in {messages}."
            )

        if len(videos) != num_video_tokens:
            raise ValueError(
                f"The number of videos does not match the number of {VIDEO_PLACEHOLDER} tokens in {messages}."
            )

        if len(audios) != num_audio_tokens:
            raise ValueError(
                f"The number of audios does not match the number of {AUDIO_PLACEHOLDER} tokens in {messages}."
            )

    def _preprocess_image(
        self, image: "ImageObject", image_max_pixels: int, image_min_pixels: int, **kwargs
    ) -> "ImageObject":
        r"""Pre-process a single image."""
        if (image.width * image.height) > image_max_pixels:

View on GitHub (pinned to f28afaf635)

Solutions

  1. For every sample, make count('<image>' in all message contents) == len(images list); add or remove placeholders/files accordingly.
  2. Sanitize placeholders: ensure exact '<image>' spelling with no extra spaces.
  3. Use exactly one <image> per turn when a single image is shared, or split the image list to match multiple placeholders.
  4. Write a pre-check script over the JSONL that reports mismatched rows before training.

Example fix

# before
{"images": ["a.jpg"], "conversations": [{"from": "human", "value": "<image> Compare <image>"}]}

# after
{"images": ["a.jpg", "b.jpg"], "conversations": [{"from": "human", "value": "<image> Compare <image>"}]}
Defensive patterns

Strategy: validation

Validate before calling

IMAGE_PH = "<image>"

def mismatched_image_rows(rows: list[dict]) -> list[int]:
    bad = []
    for i, r in enumerate(rows):
        n = sum(m.get("value", m.get("content", "")).count(IMAGE_PH) for m in r.get("conversations", []))
        if n != len(r.get("images", [])):
            bad.append(i)
    return bad

Prevention

When it happens

Trigger: A multimodal row whose 'images' list length differs from the count of <image> tags in the conversations (e.g. two placeholders but one image path, or placeholders removed but images kept); also placeholder typos such as < image > that silently fail to count.

Common situations: Hand-edited conversation files where an <image> tag was deleted or added; datasets converted from other formats that append a default image to every turn; multiple images per turn without matching placeholder counts; whitespace-corrupted tags.

Related errors


AI-assisted analysis of hiyouga/LlamaFactory@f28afaf635 (2026-08-14). Data as JSON: /api/errors/1e23e14feb4a1637. Report an issue: GitHub.