huggingface/transformers · error · ValueError

You must provide only one of `prefix_to_add` and `prefix_to_

Error message

You must provide only one of `prefix_to_add` and `prefix_to_remove`

What it means

Raised by PrefixChange.__init__ (core_model_loading.py:1100). This transform either adds a key prefix or removes one — exactly one action per instance. The XOR check `(prefix_to_add is None) ^ (prefix_to_remove is not None)` raises when BOTH arguments are None (nothing to do, almost certainly a caller bug) or when BOTH are provided (ambiguous direction).

Source

Thrown at src/transformers/core_model_loading.py:1100


class PrefixChange(WeightRenaming):
    """
    Special case of WeightRenaming, used to simplify adding/removing full parts of a weight name. The regexes
    that are needed for such operations are complex, so this is a much easier API for such cases.
    """

    __slots__ = (
        "prefix_to_add",
        "prefix_to_remove",
        "model_prefix",
    )

    def __init__(
        self, prefix_to_add: str | None = None, prefix_to_remove: str | None = None, model_prefix: str | None = None
    ):
        if (prefix_to_add is None) ^ (prefix_to_remove is not None):
            raise ValueError("You must provide only one of `prefix_to_add` and `prefix_to_remove`")

        self.prefix_to_add = prefix_to_add
        self.prefix_to_remove = prefix_to_remove
        self.model_prefix = "" if model_prefix is None else model_prefix
        prefix = rf"{self.model_prefix}\." if self.model_prefix != "" else ""

        if prefix_to_add is not None:
            super().__init__(
                # We use a lookbehind to avoid adding the prefix if we detect that it's already present
                source_patterns=rf"^{prefix}(?:(?!{prefix_to_add}\.))(.+)$",
                target_patterns=rf"{prefix}{prefix_to_add}\.\1",
            )
        else:
            super().__init__(source_patterns=rf"^{prefix}{prefix_to_remove}\.(.+)$", target_patterns=rf"{prefix}\1")

    def reverse_transform(self) -> WeightTransform:
        """Reverse the current `WeightTransform` instance, to be able to save with the opposite weight transformations."""
        # TODO: check this and relax when quantizer have `reverse_op`

View on GitHub (pinned to a597f97485)

Solutions

  1. Pass exactly one of prefix_to_add or prefix_to_remove.
  2. Use keyword arguments to make the intent explicit.
  3. If your code computes prefixes conditionally, assert that exactly one is non-None before constructing.

Example fix

# before
PrefixChange(prefix_to_add='visual', prefix_to_remove='visual')  # raises

# after
PrefixChange(prefix_to_add='visual')
# or
PrefixChange(prefix_to_remove='visual')
Defensive patterns

Strategy: validation

Validate before calling

assert (prefix_to_add is None) != (prefix_to_remove is None), (
    'provide exactly one of prefix_to_add / prefix_to_remove'
)

Type guard

def is_exactly_one_set(*vals) -> bool:
    return sum(v is not None for v in vals) == 1

Prevention

When it happens

Trigger: PrefixChange() with no arguments, or PrefixChange(prefix_to_add='visual', prefix_to_remove='visual'). Also triggered by code that passes both because it copies defaults.

Common situations: Programmatically building prefix transforms and passing the same variable to both parameters, or forgetting to pass either. Common in scripts that migrate key prefixes between checkpoint formats (e.g. adding/removing 'model.' or 'vision_tower.').

Related errors


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