huggingface/transformers · error · ValueError

Multiple different capturing groups found in target_patterns

Error message

Multiple different capturing groups found in target_patterns: {unique_capturing_groups}. All target patterns must use the same capturing group pattern.

What it means

Raised in WeightTransform.__init__ (core_model_loading.py:809) while validating regex capturing groups. Target patterns may carry at most ONE distinct capturing-group pattern across the whole list (e.g. all targets use the same '(\d+)' style group), because reverse mapping substitutes matched group content back into source patterns via a single \1 backreference. If two target patterns use different capturing groups, the reverse mapping becomes ambiguous and init fails.

Solutions

  1. Make every target pattern use the IDENTICAL capturing group substring (same regex text inside the parentheses).
  2. Replace extra variation with non-capturing groups (?:...) or plain literals.
  3. If two genuinely different group structures are needed, split into two separate WeightTransform/WeightConverter instances.

Example fix

# before
WeightTransform(source_patterns=[r'blk.(\d+).*'], target_patterns=[r'layers.(\d+)', r'layers.attn.(\d+.\w+)'])

# after: single shared capturing group shape
WeightTransform(source_patterns=[r'blk.(\d+).*'], target_patterns=[r'layers.\1.q_proj', r'layers.\1.k_proj'])
Defensive patterns

Strategy: validation

Validate before calling

groups = {m.group(1) for p in target_patterns if (m := re.search(r'\((?!\?:)[^)]*\)', p))}
assert len(groups) <= 1, f'multiple distinct capturing groups: {groups} — unify them or split into two transforms'

Prevention

When it happens

Trigger: Constructing a WeightTransform/WeightConverter where target_patterns = [r'layers.(\d+).q_proj', r'model.layers.(\d+.attn).k_proj'] — i.e. two different capturing-group shapes. Also triggered by patterns with multiple nested groups in different arrangements across targets.

Common situations: Hand-writing conversion recipes for multi-layer models; authors naturally write per-layer regexes and accidentally vary the group structure (e.g. one target captures the index, another captures 'index.attn'). Usually a recipe-authoring bug caught at import/init time.

Related errors


AI-assisted analysis of huggingface/transformers@a597f97485 (2026-08-14). Data as JSON: /api/errors/7ad583927afe07ec. Report an issue: GitHub.

Appendix: source

Thrown at src/transformers/core_model_loading.py:809

        self.base_model_prefix: str | None = None

        # We need to process a few exceptions here when instantiating the reverse mapping (i.e. the targets become
        # sources, and sources become targets). The issues lie in the sources usually, so here we need to check the
        # targets for the reversed mapping

        # Process target_patterns: detect capturing groups and replace with \1
        # Store the original capturing group patterns for reverse mapping
        target_capturing_groups: list[str] = []
        for i, pattern in enumerate(self.target_patterns):
            self.target_patterns[i], captured_group = process_target_pattern(pattern)
            if captured_group is not None:
                target_capturing_groups.append(captured_group)

        # Validate that we only have one unique capturing group pattern across all targets
        # This ensures deterministic reverse mapping when sources have \1 backreferences
        unique_capturing_groups = set(target_capturing_groups)
        if len(unique_capturing_groups) > 1:
            raise ValueError(
                f"Multiple different capturing groups found in target_patterns: {unique_capturing_groups}. "
                f"All target patterns must use the same capturing group pattern."
            )
        unique_capturing_group = unique_capturing_groups.pop() if unique_capturing_groups else None

        # We also need to check capturing groups in the sources during reverse mapping (e.g. timm_wrapper, sam3)
        for i, pattern in enumerate(self.source_patterns):
            # Replace capturing groups
            if r"\1" in pattern:
                if unique_capturing_group is None:
                    raise ValueError(
                        f"Source pattern '{pattern}' contains \\1 backreference, but no capturing groups "
                        f"found in target_patterns."
                    )
                # Use the unique capturing group from target_patterns for all sources
                pattern = pattern.replace(r"\1", unique_capturing_group, 1)
            # Potentially process a bit more for consistency - only if they are consistent pairs, i.e. the length is the same
            if len(self.source_patterns) == len(self.target_patterns):

View on GitHub (pinned to a597f97485)