{"record":{"id":"e0701785bf2c9223","repo":"invoke-ai/InvokeAI","slug":"krea-2-lora-has-conflicting-layers-that-normalize","errorCode":null,"errorMessage":"Krea-2 LoRA has conflicting layers that normalize to the same target '{converted_key}'. This mixed layout is unsupported - refusing to silently drop one of the layers.","messagePattern":"Krea-2 LoRA has conflicting layers that normalize to the same target '(.+?)'\\. This mixed layout is unsupported - refusing to silently drop one of the layers\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py","lineNumber":110,"sourceCode":"        key = key.replace(native, diffusers)\n    return key\n\n\ndef _maybe_convert_native_krea2_state_dict(\n    state_dict: Dict[str, torch.Tensor],\n) -> Dict[str, torch.Tensor]:\n    \"\"\"Rewrite native (ComfyUI) Krea-2 LoRA keys to the diffusers layout, leaving diffusers keys untouched.\"\"\"\n    str_keys = [k for k in state_dict.keys() if isinstance(k, str)]\n    if not _looks_like_native_krea2_lora(str_keys):\n        return state_dict\n    converted_state_dict: Dict[str, torch.Tensor] = {}\n    for key, value in state_dict.items():\n        # `.pt`/`.ckpt` sources can carry non-string keys. They are never native Krea-2 keys, but the\n        # substring tests in `_looks_like_native_krea2_key` raise TypeError rather than returning False.\n        is_native = isinstance(key, str) and _looks_like_native_krea2_key(key)\n        converted_key = _native_krea2_key_to_diffusers(key) if is_native else key\n        if converted_key in converted_state_dict:\n            raise ValueError(\n                f\"Krea-2 LoRA has conflicting layers that normalize to the same target '{converted_key}'. \"\n                \"This mixed layout is unsupported - refusing to silently drop one of the layers.\"\n            )\n        converted_state_dict[converted_key] = value\n    return converted_state_dict\n\n\n# --- Kohya / LyCORIS (flattened) -> native key mapping ---------------------------------------------------------\n# sd-scripts and LyCORIS flatten the module path (``path.replace(\".\", \"_\")``) and prefix it with\n# ``lora_unet_``, e.g. ``lora_unet_blocks_6_attn_wv.lora_down.weight``. Flattening is lossy — nothing in the key\n# records where a '_' used to be a '.' — so we reconstruct the dotted path against the native module vocabulary\n# below and accept it only if it lands on a leaf. A key we cannot reconstruct with certainty is left untouched\n# rather than rewritten into a plausible-looking key that matches no module.\n_KREA2_KOHYA_PREFIX = \"lora_unet_\"\n\n# Native Krea-2 transformer/text-fusion block leaves. Only the Linears are listed: the non-Linear natives\n# (``mod.lin``, ``prenorm``/``postnorm``, ``attn.qknorm.*``, ``last.norm``/``last.modulation``) have no Linear\n# counterpart in the diffusers layout — ``mod.lin`` for instance is folded into the ``scale_shift_table``","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/patches/lora_conversions/krea2_lora_conversion_utils.py#L92-L128","documentation":"This error is raised while converting a native Krea-2 LoRA state dict to diffusers key format. Two distinct source keys normalize to the same converted target key, so one would silently overwrite the other and drop weights. The loader refuses the mixed-layout file rather than producing a corrupt model.","triggerScenarios":"Calling lora_model_from_krea2_state_dict on a state dict where, after _native_krea2_key_to_diffusers conversion, two different keys (e.g. a native Krea-2 key and an already-diffusers-format key for the same layer) map to the same converted_key.","commonSituations":"LoRA files that bundle both native Krea-2 keys and diffusers-style keys for the same module (e.g. assembled from multiple checkpoints or exported by tools that duplicate layers); manually merged state dicts; keys that collide only after prefix stripping/normalization.","solutions":["Open the LoRA file and remove the duplicate layer(s) so each logical layer appears under exactly one key layout.","Re-export the LoRA from its trainer in a single, consistent key format (all-native Krea-2 or all-diffusers).","If merging two LoRAs, merge their tensors into one key instead of keeping both variants of the same layer."],"exampleFix":"// before: state dict contains both\ndiffusion_model.blocks.0.attn.qkv.lora_down.weight\ntransformer.blocks.0.attn.qkv.lora_down.weight\n// after: keep exactly one variant per logical layer\ndiffusion_model.blocks.0.attn.qkv.lora_down.weight","handlingStrategy":"validation","validationCode":"from invokeai.backend.patches.lora_conversions.krea2_lora_conversion_utils import _looks_like_native_krea2_key, _native_krea2_key_to_diffusers\nseen = set()\nfor key in state_dict:\n    k = _native_krea2_key_to_diffusers(key) if isinstance(key, str) and _looks_like_native_krea2_key(key) else key\n    if k in seen:\n        raise ValueError(f'duplicate normalized key: {k}')\n    seen.add(k)","typeGuard":"def has_no_krea2_key_collisions(state_dict: dict) -> bool:\n    seen = set()\n    for key in state_dict:\n        k = str(key)\n        if k in seen:\n            return False\n        seen.add(k)\n    return True","tryCatchPattern":"try:\n    model = lora_model_from_krea2_state_dict(state_dict)\nexcept ValueError as e:\n    if 'conflicting layers' in str(e):\n        logger.error('LoRA file has duplicate layers: %s', e)\n        # inspect and deduplicate state_dict keys before retrying\n    else:\n        raise","preventionTips":["Never concatenate state dicts from two LoRA exports of the same model.","Deduplicate keys before loading; keep exactly one tensor per logical layer.","Prefer files exported by a single trainer with one key convention."],"tags":["lora","state-dict","key-collision","krea2"],"backgroundTag":"duplicate-key-collision","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}