{"record":{"id":"4275993a2d937764","repo":"hiyouga/LlamaFactory","slug":"the-number-of-videos-does-not-match-the-number-of","errorCode":null,"errorMessage":"The number of videos does not match the number of {VIDEO_PLACEHOLDER} tokens in {messages}.","messagePattern":"The number of videos does not match the number of (.+?) tokens in (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/data/mm_plugin.py","lineNumber":214,"sourceCode":"        r\"\"\"Validate if the number of images, videos and audios match the number of placeholders in messages.\"\"\"\n        num_image_tokens, num_video_tokens, num_audio_tokens = 0, 0, 0\n        for message in messages:\n            num_image_tokens += message[\"content\"].count(IMAGE_PLACEHOLDER)\n            num_video_tokens += message[\"content\"].count(VIDEO_PLACEHOLDER)\n            num_audio_tokens += message[\"content\"].count(AUDIO_PLACEHOLDER)\n\n        if len(images) != num_image_tokens:\n            raise ValueError(\n                f\"The number of images does not match the number of {IMAGE_PLACEHOLDER} tokens in {messages}.\"\n            )\n\n        if len(videos) != num_video_tokens:\n            raise ValueError(\n                f\"The number of videos does not match the number of {VIDEO_PLACEHOLDER} tokens in {messages}.\"\n            )\n\n        if len(audios) != num_audio_tokens:\n            raise ValueError(\n                f\"The number of audios does not match the number of {AUDIO_PLACEHOLDER} tokens in {messages}.\"\n            )\n\n    def _preprocess_image(\n        self, image: \"ImageObject\", image_max_pixels: int, image_min_pixels: int, **kwargs\n    ) -> \"ImageObject\":\n        r\"\"\"Pre-process a single image.\"\"\"\n        if (image.width * image.height) > image_max_pixels:\n            resize_factor = math.sqrt(image_max_pixels / (image.width * image.height))\n            width, height = int(image.width * resize_factor), int(image.height * resize_factor)\n            image = image.resize((width, height))\n\n        if (image.width * image.height) < image_min_pixels:\n            resize_factor = math.sqrt(image_min_pixels / (image.width * image.height))\n            width, height = int(image.width * resize_factor), int(image.height * resize_factor)\n            image = image.resize((width, height))\n\n        if image.mode != \"RGB\":","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/data/mm_plugin.py#L196-L232","documentation":"Thrown by BasePlugin._validate_messages during message preprocessing for any multimodal model. The number of video objects passed in the `videos` argument must equal the number of `<video>` (VIDEO_PLACEHOLDER) tokens embedded in the message content. LlamaFactory replaces each placeholder with one video, so a mismatch would desynchronize media and tokens.","triggerScenarios":"Calling get_mm_plugin(...).process_messages(messages, images, videos, ...) or running training/inference where a sample's `messages` contain N `<video>` tags but the dataset row supplies a `videos` list of length != N. Typical rows: two `<video>` tags with one video file, or a video column but no `<video>` tag in the prompt.","commonSituations":"Hand-written JSON datasets where the prompt template and the media columns drift apart; converting a dataset from images to videos (or mixed samples) without updating the instruction text; extra whitespace or a typo like `<vid>` making the placeholder uncountable.","solutions":["Count VIDEO_PLACEHOLDER occurrences in each sample's messages and make the `videos` list length match exactly (one video per <video> tag).","If the sample has no video, remove the <video> tag from the content string.","If a video column exists but the prompt lacks the tag, add <video> to the prompt (e.g. 'Describe the video: <video>').","Write a small preprocessing script that asserts content.count('<video>') == len(videos) for every row before training."],"exampleFix":"// before\n{\"messages\": [{\"role\": \"user\", \"content\": \"Compare <video> and <video>.\"}], \"videos\": [\"a.mp4\"]}\n// after\n{\"messages\": [{\"role\": \"user\", \"content\": \"Compare <video> and <video>.\"}], \"videos\": [\"a.mp4\", \"b.mp4\"]}","handlingStrategy":"validation","validationCode":"from llamafactory.data.mm_plugin import VIDEO_PLACEHOLDER\n\ndef check_sample(messages, videos):\n    n = sum(m['content'].count(VIDEO_PLACEHOLDER) for m in messages if 'content' in m)\n    assert n == len(videos), f'{n} <video> tags vs {len(videos)} videos'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep placeholder tags and media columns in the same dataset row and generate them together in the prep script.","Run a dry dataset validation pass (iterate rows, assert tag counts == media counts) before launching training."],"tags":["multimodal","video","dataset-validation","data-preprocessing"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}