{"record":{"id":"a0ac21360dd75d51","repo":"huggingface/transformers","slug":"source-keys-self-source-patterns-target-pattern","errorCode":null,"errorMessage":"source keys={self.source_patterns}, target_patterns={self.target_patterns} but you can only have one to many, one to one or many to one.","messagePattern":"source keys=(.+?), target_patterns=(.+?) but you can only have one to many, one to one or many to one\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/core_model_loading.py","lineNumber":1150,"sourceCode":"_INTERNAL_MANY_TO_MANY_CONVERSIONS = (\n    ErnieFuseAndSplitTextVisionExperts,\n    ErnieSplitAndDecoupleTextVisionExperts,\n)\n\n\nclass WeightConverter(WeightTransform):\n    __slots__ = (\"operations\",)\n\n    def __init__(\n        self, source_patterns: str | list[str], target_patterns: str | list[str], operations: list[ConversionOps]\n    ):\n        super().__init__(source_patterns, target_patterns)\n        self.operations: list[ConversionOps] = operations\n\n        if bool(len(self.source_patterns) - 1) + bool(len(self.target_patterns) - 1) >= 2:\n            # We allow many-to-many only if we use an internal operation that can handle it\n            if not any(isinstance(op, _INTERNAL_MANY_TO_MANY_CONVERSIONS) for op in self.operations):\n                raise ValueError(\n                    f\"source keys={self.source_patterns}, target_patterns={self.target_patterns} but you can only have one to many, one to one or many to one.\"\n                )\n        if not self.operations:\n            raise ValueError(\"WeightConverter requires at least one operation.\")\n\n    def convert(\n        self,\n        layer_name: str,\n        model=None,\n        config=None,\n        hf_quantizer=None,\n        loading_info: LoadStateDictInfo | None = None,\n    ):\n        # Collect the tensors here - we use a new dictionary to avoid keeping them in memory in the internal\n        # attribute during the whole process\n        collected_tensors = self.materialize_tensors()\n\n        for op in self.operations:","sourceCodeStart":1132,"sourceCodeEnd":1168,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/core_model_loading.py#L1132-L1168","documentation":"Raised by WeightConverter.__init__ (core_model_loading.py:1150). Conversions support 1:1, 1:N and N:1 pattern cardinalities; N:N (many sources to many targets) is only legal when at least one operation in the chain is a specially supported internal op (currently the Ernie fuse/split text-vision expert ops, see _INTERNAL_MANY_TO_MANY_CONVERSIONS at core_model_loading.py:1132). Any other N:N combination has no defined tensor-routing semantics and is rejected at construction.","triggerScenarios":"WeightConverter(source_patterns=[p1, p2], target_patterns=[t1, t2], operations=[SomeOp()]) where SomeOp is not ErnieFuseAndSplitTextVisionExperts / ErnieSplitAndDecoupleTextVisionExperts (e.g. Chunk, Permute, or a custom ConversionOps subclass).","commonSituations":"Recipe authors trying to merge multiple checkpoint keys into multiple target keys in one converter (e.g. combining gate+up into two different fused targets) with generic ops. The framework cannot know how to pair sources with targets for arbitrary ops.","solutions":["Split the N:N converter into separate 1:1 / 1:N / N:1 WeightConverter instances chained in order.","If the conversion is genuinely many-to-many tensor routing (like Ernie expert fusion), implement/reuse an op registered in _INTERNAL_MANY_TO_MANY_CONVERSIONS.","Re-express the mapping: use N:1 (many sources fused to one target via Concatenate-like ops) followed by 1:N (Chunk) converters in sequence."],"exampleFix":"# before\nWeightConverter(source_patterns=[r'a.*', r'b.*'], target_patterns=[r'x.*', r'y.*'], operations=[MyOp()])  # raises\n\n# after: two chained converters\nWeightConverter(source_patterns=[r'a.*', r'b.*'], target_patterns=[r'fused'], operations=[Concatenate(dim=0)])\nWeightConverter(source_patterns=[r'fused'], target_patterns=[r'x.*', r'y.*'], operations=[Chunk(dim=0)])","handlingStrategy":"validation","validationCode":"n_src, n_tgt = len(source_patterns), len(target_patterns)\nmany_to_many = n_src > 1 and n_tgt > 1\ninternal = {type(op).__name__ for op in operations} & {'ErnieFuseAndSplitTextVisionExperts', 'ErnieSplitAndDecoupleTextVisionExperts'}\nassert not (many_to_many and not internal), 'N:N requires an internal many-to-many op; split into chained converters'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Design recipes as chains of 1:1 / 1:N / N:1 converters; never N:N with generic ops.","Reserve N:N for the whitelisted internal ops (Ernie expert fuse/split).","When review shows two multi-pattern lists meeting in one WeightConverter, refactor into two stages (N:1 fuse, then 1:N split)."],"tags":["weight-conversion","cardinality","validation","programmer-error"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}