{"record":{"id":"2113abbd0a195e5e","repo":"invoke-ai/InvokeAI","slug":"model-does-not-match-wan-lora-heuristics","errorCode":null,"errorMessage":"model does not match Wan LoRA heuristics","messagePattern":"model does not match Wan LoRA heuristics","errorType":"exception","errorClass":"NotAMatchError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/configs/lora.py","lineNumber":1136,"sourceCode":"            state_dict,\n            {\n                \"lora_A.weight\",\n                \"lora_B.weight\",\n                \"lora_down.weight\",\n                \"lora_up.weight\",\n                \"dora_scale\",\n                \".lokr_w1\",\n                \".lokr_w2\",\n            },\n        )\n\n        # Reject if any non-Wan architecture signature is present. Without this\n        # guard a Wan LoRA could be falsely identified by Anima (cross_attn /\n        # self_attn name collision) or vice versa.\n        if has_wan_keys and has_lora_suffix and not has_non_wan_architecture_keys(str_keys):\n            return\n\n        raise NotAMatchError(\"model does not match Wan LoRA heuristics\")\n\n    @classmethod\n    def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType:\n        state_dict = mod.load_state_dict()\n        str_keys = [k for k in state_dict.keys() if isinstance(k, str)]\n\n        if (has_wan_kohya_keys(str_keys) or has_wan_peft_keys(str_keys)) and not has_non_wan_architecture_keys(\n            str_keys\n        ):\n            return BaseModelType.Wan\n\n        raise NotAMatchError(\"model does not look like a Wan LoRA\")\n\n    @classmethod\n    def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self:\n        # Run the base-class probe (file-check, lora-suffix, base detection).\n        instance = super().from_model_on_disk(mod, override_fields)\n","sourceCodeStart":1118,"sourceCodeEnd":1154,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/lora.py#L1118-L1154","documentation":"NotAMatchError raised by LoRA_LyCORIS_Wan_Config._validate_looks_like_lora when a candidate file fails the Wan LoRA heuristic test: it must simultaneously have Wan-style keys (has_wan_kohya_keys or has_wan_peft_keys), a LoRA/LoKR weight suffix (lora_A.weight, lora_down.weight, dora_scale, lokr_w1, etc.), and NO non-Wan architecture signature keys. This guard prevents Anima/Wan cross-identification caused by shared cross_attn/self_attn naming. It is thrown during from_model_on_disk probing so the router can fall through to other config classes.","triggerScenarios":"Probing a file via from_model_on_disk where any of the three conditions fails: (1) keys do not match Wan kohya/peft patterns (attn1/attn2/ffn.net or self_attn/cross_attn/ffn.N), (2) no lora_A/lora_down/dora_scale/lokr suffixes present (e.g. a full main-model checkpoint, not a LoRA), or (3) has_non_wan_architecture_keys finds signatures of another architecture (e.g. Anima _proj-suffixed attention or mlp/adaln_modulation names).","commonSituations":"Pointing the installer at a full Wan transformer checkpoint instead of a LoRA; a mixed/multi-architecture LoRA dump; a LyCORIS file with unusual suffixes; an Anima LoRA being probed and correctly rejected by the Wan class (the error itself is expected probe behavior when the file is simply not a Wan LoRA).","solutions":["Confirm the file is a Wan LoRA (keys like blocks.*.self_attn / attn1 / ffn.net with lora_down.weight or lora_A.weight suffixes); if it's a main model or another architecture's LoRA, install it through the right import path/category.","Inspect state-dict keys with safetensors and check for foreign architecture signatures (mlp, adaln_modulation, *_proj) that trip has_non_wan_architecture_keys; rename/convert keys if mislabeled.","If it's a DoRA/LoKR variant, make sure suffixes (dora_scale, lokr_w1/w2) survived export; re-export with standard Kohya/LyCORIS tooling.","If you believe the file IS a Wan LoRA, file an issue with the key list — the heuristic may need a new pattern."],"exampleFix":"// before (Anima-flavored key, rejected by Wan probe)\n// 'lora_unet_blocks_0_cross_attn.k_proj.lora_down.weight'\n// after (Wan-style key)\n// 'lora_unet_blocks_0_cross_attn.k.lora_down.weight'","handlingStrategy":"validation","validationCode":"from safetensors.torch import load_file\nsd = load_file(path)\nkeys = list(sd.keys())\nhas_wan = any(('attn1' in k or 'attn2' in k or 'ffn.net' in k or 'self_attn' in k or 'cross_attn' in k) for k in keys)\nhas_lora_suffix = any(k.endswith(('lora_A.weight', 'lora_B.weight', 'lora_down.weight', 'lora_up.weight', 'dora_scale', '.lokr_w1', '.lokr_w2')) for k in keys)\nforeign = any(('adaln_modulation' in k or ('_proj' in k and 'cross_attn' in k)) for k in keys)\nif not (has_wan and has_lora_suffix and not foreign):\n    raise ValueError(f'{path} does not satisfy Wan LoRA heuristics')","typeGuard":"def looks_like_wan_lora(keys: list[str]) -> bool:\n    wan = any(('self_attn' in k or 'cross_attn' in k or 'attn1' in k or 'attn2' in k or 'ffn' in k) for k in keys)\n    suffix = any(k.endswith(('lora_down.weight', 'lora_A.weight', 'dora_scale', 'lokr_w1', 'lokr_w2')) for k in keys)\n    return wan and suffix and not any(('adaln_modulation' in k or 'mlp.layer_0.lora' in k) for k in keys)","tryCatchPattern":"try:\n    instance = LoRA_LyCORIS_Wan_Config.from_model_on_disk(mod, overrides)\nexcept NotAMatchError as e:\n    logger.info('File rejected as Wan LoRA: %s', e)\n    instance = try_other_lora_configs(mod, overrides)","preventionTips":["Download Wan LoRAs from sources that ship standard Kohya or diffusers key layouts.","Don't point the installer at full Wan transformer checkpoints expecting LoRA handling.","Inspect keys before install when merging multi-architecture LoRAs.","Keep probe-order-sensitive archs (Anima/Wan) in separate install batches to avoid confusion."],"tags":["model-manager","lora","heuristic-mismatch","invokeai"],"backgroundTag":"model-format-not-matched","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}