{"record":{"id":"39b79f279b2410ec","repo":"hiyouga/LlamaFactory","slug":"merged-position-ids-shape-mismatch-got-features","errorCode":null,"errorMessage":"Merged position_ids shape mismatch: got {features['position_ids'].shape}, expected {expected_position_ids_shape}.","messagePattern":"Merged position_ids shape mismatch: got (.+?), expected (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/data/collator.py","lineNumber":321,"sourceCode":"        expected_position_ids_shape = (\n            (bsz, seq_len)\n            if all_position_ids[0].dim() == 2\n            else (\n                all_position_ids[0].size(0),\n                bsz,\n                seq_len,\n            )\n        )\n        # Check if position_ids shape matches expected shape.\n        # for further usage, we should padding to the right when some padding token on the right.\n        if has_dummy_image:\n            features[\"position_ids\"] = torch.cat([features[\"position_ids\"], dummy_image_right_padding_mrope], dim=-1)\n            features[\"attention_mask\"] = torch.cat(\n                [features[\"attention_mask\"], dummy_image_right_padding_attention_mask], dim=-1\n            )\n\n        if features[\"position_ids\"].shape != expected_position_ids_shape:\n            raise ValueError(\n                \"Merged position_ids shape mismatch: \"\n                f\"got {features['position_ids'].shape}, expected {expected_position_ids_shape}.\"\n            )\n\n    def __call__(self, features: list[dict[str, Any]]) -> dict[str, \"torch.Tensor\"]:\n        model_type = getattr(getattr(self.model, \"config\", None), \"model_type\", None)\n        is_moss_vl = model_type == \"moss_vl\"\n        batch_images, batch_videos, batch_audios = [], [], []\n        batch_imglens, batch_vidlens, batch_audlens, batch_input_ids = [], [], [], []\n        packing_params_list: list[dict[str, Any] | None] = []\n        for feature in features:\n            images = feature.pop(\"images\", None) or []\n            videos = feature.pop(\"videos\", None) or []\n            audios = feature.pop(\"audios\", None) or []\n            batch_images.extend(images)\n            batch_videos.extend(videos)\n            batch_audios.extend(audios)\n            batch_imglens.append(len(images))","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/data/collator.py#L303-L339","documentation":"During multimodal feature merging, after concatenating the dummy-image right-padding onto position_ids, the code compares features['position_ids'].shape against a precomputed expected_position_ids_shape and raises ValueError on mismatch. A mismatch means the mrope position computation produced a sequence length inconsistent with the (possibly padded) input_ids/attention_mask — almost always an image-token-count disagreement between the template's placeholder tokens and what the mm_plugin actually expanded.","triggerScenarios":"Training a VLM (qwen2-vl/qwen2.5 style mrope models) where the number of <image> expansion tokens in the encoded example differs from what the processor returns (e.g. image processed at a different resolution/grid, dummy image injection with has_dummy_image, or a template not designed for the model's mm token counting).","commonSituations":"Custom or mismatched template for qwen2-vl family; transformers version change altering image token expansion counts; enabling has_dummy_image paths on batches whose attention_mask was padded differently; corrupt image files producing zero-size patches.","solutions":["Verify you are using the template registered for your model family (e.g. qwen2_vl / qwen2_5_vl), not a generic one.","Pin/downgrade transformers to a version known compatible with your LlamaFactory release — image token counting changed across 4.49-4.52.","Re-run data preprocessing (clear the cached tokenized dataset) after changing template or processor settings.","If it happens only on specific samples, inspect those images (corrupt, extreme aspect ratio) and drop or fix them.","Report with full repro if it persists on stock configs — the padding bookkeeping in the dummy-image path may need a fix."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# preflight one batch before training\ncollator = MultiModalDataCollatorForSeq2Seq(tokenizer=tokenizer, model=model, template=template)\nsample = collator([next(iter(train_dataset))])\nassert \"position_ids\" not in sample or sample[\"position_ids\"].shape[-1] == sample[\"input_ids\"].shape[-1]","typeGuard":null,"tryCatchPattern":"try:\n    batch = collator(features)\nexcept ValueError as e:\n    if \"position_ids shape mismatch\" in str(e):\n        # dump the offending sample ids for triage, then abort run\n        logger.error(\"mrope mismatch on batch; check template/transformers pairing\")\n        raise","preventionTips":["Lock the (LlamaFactory, transformers) version pair that worked for your VLM.","Clear tokenization caches after any template/processor change.","Run a 1-batch dry run through the collator before long jobs."],"tags":["collator","mrope","multimodal","tensor-shape","training"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}