{"record":{"id":"f339e41aa3c4af0d","repo":"huggingface/transformers","slug":"cannot-reverse-the-transform-with-tp-or-quantizati","errorCode":null,"errorMessage":"Cannot reverse the transform with TP or quantization","messagePattern":"Cannot reverse the transform with TP or quantization","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/core_model_loading.py","lineNumber":924,"sourceCode":"        source_pattern_that_matched = self.source_patterns[int(matching_group_name[1:])]\n        # If we matched, we always replace with the first target pattern, in case we have several (one to many transform)\n        replacement = self.target_patterns[0]\n        # Allow capturing groups in patterns, i.e. to add a prefix to all keys (e.g. timm_wrapper, sam3)\n        if r\"\\1\" in replacement:\n            # The index of the internal group we need to replace is the index of the matched named group as it comes\n            # inside that matched named group\n            replaced_group_idx = self.compiled_sources.groupindex[matching_group_name] + 1\n            replacement = replacement.replace(r\"\\1\", match_object.group(replaced_group_idx))\n        renamed_key = key_to_match.replace(match_object.group(0), replacement, 1)\n        if prefix_dot is not None:\n            renamed_key = prefix_dot + renamed_key\n        return renamed_key, source_pattern_that_matched\n\n    def reverse_transform(self) -> WeightTransform:\n        \"\"\"Reverse the current `WeightTransform` instance, to be able to save with the opposite weight transformations.\"\"\"\n        # TODO: check this and relax when quantizer have `reverse_op`\n        if self.quantization_operation is not None:\n            raise ValueError(\"Cannot reverse the transform with TP or quantization\")\n\n        kwargs = {}\n        # Add the reverse ops if applicable (it needs to be provided at __init__)\n        if hasattr(self, \"operations\"):\n            # All reverse ops, in reverse order\n            kwargs[\"operations\"] = [op.reverse_op for op in self.operations[::-1]]\n\n        reverse_transform = self.__class__(\n            source_patterns=self._original_target_patterns, target_patterns=self._original_source_patterns, **kwargs\n        )\n        reverse_transform.scope_prefix = self.scope_prefix\n        reverse_transform.base_model_prefix = self.base_model_prefix\n        return reverse_transform\n\n    def materialize_tensors(self) -> dict[str, list[torch.Tensor]]:\n        \"\"\"\n        Materialize all the tensors that were saved in `self.collected_tensors`. This function removes them from the\n        internal attribute to avoid keeping them in memory during the different `self.convert` operations, and return","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/core_model_loading.py#L906-L942","documentation":"Raised by WeightTransform.reverse_transform (core_model_loading.py:924). Reversing a transform builds the inverse operations so an HF model can be saved back in the original checkpoint layout, but quantization operations have no reverse_op yet (see the TODO in the source). If the transform carries a quantization_operation (e.g. the weights were dequantized from FP8/GPTQ on load), reversal is impossible and the method refuses.","triggerScenarios":"Calling model.save_pretrained(..., convert_to_original=True) or transform.reverse_transform() on a model whose conversion pipeline included a quantizer (Fp8, bitsandbytes, etc.), i.e. quantization_operation is not None on the transform.","commonSituations":"Trying to round-trip a checkpoint that was loaded through a quantizer path: convert original checkpoint -> HF (with dequantization) -> attempt to save back to original format. The quantized -> original re-quantization step is not implemented, so this direction is blocked.","solutions":["Do not request the reverse/original save for quantized checkpoints; save in HF format instead (omit the convert-to-original option).","Start from the non-quantized original checkpoint if you need a round trip back to the original layout.","Track the upstream TODO: once quantizers implement reverse_op this restriction may be relaxed — check your transformers version."],"exampleFix":"# before\nmodel.save_pretrained(out_dir, convert_to_original=True)  # model was fp8-dequantized on load -> raises\n\n# after\nmodel.save_pretrained(out_dir)  # save in HF format; original-layout export unsupported for quantized loads","handlingStrategy":"type-guard","validationCode":"def can_reverse(transform) -> bool:\n    return transform.quantization_operation is None","typeGuard":"def is_reversible(transform) -> bool:\n    return getattr(transform, 'quantization_operation', None) is None","tryCatchPattern":"try:\n    reverse = transform.reverse_transform()\nexcept ValueError:\n    # quantized load: save in HF layout instead\n    model.save_pretrained(out_dir)","preventionTips":["Check transform.quantization_operation is None before requesting original-layout export.","Keep an unquantized copy of the source checkpoint when round trips are required.","Gate convert-to-original saving behind a capability check in your export tooling."],"tags":["quantization","reverse-conversion","save-pretrained","unsupported-operation"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}