{"record":{"id":"7a1a60cd2faa338c","repo":"huggingface/transformers","slug":"expected-exactly-one-kernel-repo-regardless-of-dev","errorCode":null,"errorMessage":"Expected exactly one kernel repo regardless of device/mode specificity, got {hub_repo}","messagePattern":"Expected exactly one kernel repo regardless of device/mode specificity, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/transformers/integrations/hub_kernels.py","lineNumber":873,"sourceCode":") -> None:\n    if not hasattr(cls, \"config_class\") or not hasattr(cls.config_class, \"model_type\"):\n        raise ValueError(f\"Model {cls.__name__} has no config_class or model_type.\")\n    model_type = cls.config_class.model_type\n\n    patch_mapping: dict[str, type] = {}\n    new_mapping: dict = {}\n\n    # We might need to instantiate the model on meta device.\n    # We do it lazily, only if we encounter a fused kernel.\n    meta_model = None\n\n    for layer_name, hub_repo in kernel_config.kernel_mapping.items():\n        if isinstance(hub_repo, (str, tuple)):\n            hub_repo = {None: hub_repo}\n\n        if isinstance(hub_repo, dict):\n            if len(hub_repo.values()) != 1:\n                raise ValueError(\n                    f\"Expected exactly one kernel repo regardless of device/mode specificity, got {hub_repo}\"\n                )\n        else:\n            raise ValueError(f\"Invalid hub repo {hub_repo!r} for layer {layer_name!r}\")\n\n        hub_repo = next(iter(hub_repo.values()))\n\n        # Infer metadata (revision/version/trust_remote_code)\n        if isinstance(hub_repo, tuple):\n            repo_str, metadata = hub_repo\n\n            revision = metadata.get(\"revision\", None)\n            version = metadata.get(\"version\", None)\n            trust_remote_code = metadata.get(\"trust_remote_code\", False) or ALLOW_ALL_KERNELS\n            metadata = {\"version\": version} if version is not None else {\"revision\": revision}\n            metadata |= {\"trust_remote_code\": trust_remote_code}\n\n            final_repo = (repo_str, metadata)","sourceCodeStart":855,"sourceCodeEnd":891,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/integrations/hub_kernels.py#L855-L891","documentation":"In a `KernelConfig.kernel_mapping`, the value for each layer name may be a plain repo string, a (repo, metadata) tuple, or a dict keyed by device/mode — but after normalization the dict must contain exactly one repo entry, because `register_kernel_replacements_and_fusions` resolves one hub repo per layer regardless of device or training/inference mode. A dict with zero or 2+ entries is rejected with this ValueError.","triggerScenarios":"Hand-writing a kernel mapping like `{\"model.layers.0.mlp\": {\"cuda\": \"repo_a\", \"cpu\": \"repo_b\"}}` (two entries), or `{\"layer\": {}}` (zero entries), and passing it as `KernelConfig(kernel_mapping=...)` to a kernelized `from_pretrained` / `register_kernel_replacements_and_fusions`. Plain string values or a single-key dict (`{None: \"repo\"}`) are accepted.","commonSituations":"Users assuming per-device kernel selection is supported and authoring multi-entry dicts; merging/combining kernel configs that accidentally produce multiple keys; empty placeholder entries left in a config file.","solutions":["Give each layer exactly one repo, ideally as a plain string: `{\"LlamaDecoderLayer\": \"kernels-community/llama-blk\"}`.","If you used a dict form, keep one key only, e.g. `{None: \"repo\"}` or one device key.","Remove empty `{}` entries from the mapping.","Do device-based selection in your own code before building the KernelConfig."],"exampleFix":"# before\nkernel_mapping = {\n    \"LlamaDecoderLayer\": {\"cuda\": \"kernels-community/llama-blk\", \"rocm\": \"kernels-community/llama-blk-rocm\"},\n}\n# ValueError: Expected exactly one kernel repo ...\n\n# after\nkernel_mapping = {\n    \"LlamaDecoderLayer\": \"kernels-community/llama-blk\",  # pick one repo per layer\n}","handlingStrategy":"validation","validationCode":"def normalize_kernel_mapping(mapping):\n    out = {}\n    for layer, repo in mapping.items():\n        if isinstance(repo, dict) and len(repo) != 1:\n            raise ValueError(f\"layer {layer!r} must map to exactly one kernel repo, got {repo}\")\n        out[layer] = next(iter(repo.values())) if isinstance(repo, dict) else repo\n    return out\n\nkernel_mapping = normalize_kernel_mapping(kernel_mapping)","typeGuard":"def is_valid_kernel_mapping(mapping: dict) -> bool:\n    return all(\n        isinstance(v, (str, tuple)) or (isinstance(v, dict) and len(v) == 1)\n        for v in mapping.values()\n    )","tryCatchPattern":"try:\n    register_kernel_replacements_and_fusions(cls, config, kernel_config)\nexcept ValueError as e:\n    if \"exactly one kernel repo\" in str(e):\n        for layer, repo in kernel_config.kernel_mapping.items():\n            if isinstance(repo, dict) and len(repo) != 1:\n                kernel_config.kernel_mapping[layer] = next(iter(repo.values())) or None\n        register_kernel_replacements_and_fusions(cls, config, kernel_config)\n    else:\n        raise","preventionTips":["Author kernel mappings as plain strings \"layer_name -> repo_id\" unless a dict is required.","Validate kernel mappings with a single-key check before constructing KernelConfig.","Do device/mode kernel selection in your own orchestration code, not inside the mapping."],"tags":["kernels","kernel-mapping","config-validation","kernelize"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}