{"record":{"id":"1b6d69e9395ac6e8","repo":"huggingface/transformers","slug":"groupweightrename-requires-n-n-length-matching-bu","errorCode":null,"errorMessage":"GroupWeightRename requires N:N length matching, but found len(source_patterns)={len(source_patterns)} != len(target_patterns)={len(target_patterns)}","messagePattern":"GroupWeightRename requires N:N length matching, but found len\\(source_patterns\\)=(.+?) != len\\(target_patterns\\)=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/core_model_loading.py","lineNumber":1035,"sourceCode":"\nclass GroupWeightRename(WeightRenaming):\n    \"\"\"\n    Applies a list of paired WeightRenaming transforms, activated lazily by the first (\"guard\")\n    source pattern.  Use this when two renames share an intermediate name (e.g. `norm0→norm1`\n    and `norm1→norm2`) so that loading an already-converted checkpoint (which has `norm1`\n    and `norm2` but no `norm0`) does not incorrectly re-apply the renames.\n\n    NOTE: order `source_patterns` so that the one that is absent in an already-converted checkpoint\n    comes first.  The state dict is iterated in sorted key order, so the guard pattern must be\n    lexicographically smaller than the dependent patterns. Otherwise the dependents will be\n    skipped on the first pass and never retried.\n    \"\"\"\n\n    __slots__ = (\"_active\",)\n\n    def __init__(self, source_patterns: list[str], target_patterns: list[str]):\n        if len(source_patterns) != len(target_patterns):\n            raise ValueError(\n                \"GroupWeightRename requires N:N length matching, but found \"\n                f\"len(source_patterns)={len(source_patterns)} != len(target_patterns)={len(target_patterns)}\"\n            )\n        super().__init__(source_patterns=source_patterns, target_patterns=target_patterns)\n        self._active = None  # None = undecided; True = guard was seen\n\n    def rename_source_key(self, source_key: str) -> tuple[str, str | None]:\n        matched = self._scoped_match(source_key)\n        if matched is None:\n            return source_key, None\n\n        prefix_dot, key_to_match, match_object = matched\n        matching_group_name = next(name for name, val in match_object.groupdict().items() if val is not None)\n        group_index = int(matching_group_name[1:])\n\n        if group_index == 0:\n            # Guard pattern matched — activate the group for subsequent keys\n            self._active = True","sourceCodeStart":1017,"sourceCodeEnd":1053,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/core_model_loading.py#L1017-L1053","documentation":"Raised by GroupWeightRename.__init__ (core_model_loading.py:1035). GroupWeightRename performs a coordinated set of renames guarded by a sentinel (guard) key, so it must have an exact 1:1 correspondence between source_patterns and target_patterns. If the two lists differ in length, the group semantics (which dependent rename maps to which guard) are undefined and construction fails immediately.","triggerScenarios":"GroupWeightRename(source_patterns=[a, b, c], target_patterns=[x, y]) — any length mismatch. Typically an editing mistake where one list was updated and the other was not.","commonSituations":"Maintaining conversion recipes that rename grouped checkpoints (e.g. norm0/norm1/norm2 style layouts where presence of one key implies the others). Adding a new pattern to source_patterns but forgetting the matching target, or vice versa.","solutions":["Count both lists and add the missing entry so len(source_patterns) == len(target_patterns).","Keep sources and targets as pairs in one list of tuples in your recipe source, then unzip — impossible to get out of sync.","Remember ordering matters too (see the class docstring: the guard pattern must sort lexicographically first)."],"exampleFix":"# before\nGroupWeightRename(source_patterns=[r'norm0', r'norm1', r'norm2'], target_patterns=[r'ln_1', r'ln_2'])\n\n# after\nGroupWeightRename(source_patterns=[r'norm0', r'norm1', r'norm2'], target_patterns=[r'ln_1', r'ln_2', r'ln_3'])","handlingStrategy":"validation","validationCode":"assert len(source_patterns) == len(target_patterns), (\n    f'GroupWeightRename needs N:N, got {len(source_patterns)} sources vs {len(target_patterns)} targets'\n)","typeGuard":"def is_paired_patterns(sources: list[str], targets: list[str]) -> bool:\n    return len(sources) == len(targets)","tryCatchPattern":null,"preventionTips":["Store rename pairs as tuples in one list and unzip at construction so lengths can never diverge.","Order patterns so the guard key sorts first (per the class docstring).","Add an init-time unit test for each recipe's pattern lists."],"tags":["weight-conversion","rename","validation","programmer-error"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}