{"record":{"id":"2dd708849e1f11e1","repo":"invoke-ai/InvokeAI","slug":"model-does-not-match-anima-lora-heuristics","errorCode":null,"errorMessage":"model does not match Anima LoRA heuristics","messagePattern":"model does not match Anima LoRA heuristics","errorType":"exception","errorClass":"NotAMatchError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/configs/lora.py","lineNumber":1063,"sourceCode":"\n        # Also check for LoRA/LoKR weight suffixes\n        has_lora_suffix = state_dict_has_any_keys_ending_with(\n            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        if has_cosmos_keys and has_lora_suffix:\n            return\n\n        raise NotAMatchError(\"model does not match Anima LoRA heuristics\")\n\n    @classmethod\n    def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType:\n        \"\"\"Anima LoRAs target Cosmos DiT blocks (blocks.X.mlp, blocks.X.adaln_modulation,\n        blocks.X.cross_attn.q_proj, etc.).\n\n        Uses the strict Cosmos-DiT detectors to be mutually exclusive with\n        Wan-LoRA detection — see ``_validate_looks_like_lora`` for rationale.\n        \"\"\"\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_cosmos_dit_kohya_keys_strict(str_keys) or has_cosmos_dit_peft_keys_strict(str_keys):\n            return BaseModelType.Anima\n\n        raise NotAMatchError(\"model does not look like an Anima LoRA\")\n\n","sourceCodeStart":1045,"sourceCodeEnd":1081,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/lora.py#L1045-L1081","documentation":"The Anima LoRA config's _validate_looks_like_lora accepts a file only when it has Cosmos DiT block keys (blocks.X.mlp, blocks.X.adaln_modulation, blocks.X.cross_attn.q_proj, etc.) AND those keys carry a LoRA suffix; both `has_cosmos_keys and has_lora_suffix` must hold. Files matching the block layout but missing LoRA suffixes — or with LoRA suffixes but no Cosmos block structure — raise this NotAMatchError.","triggerScenarios":"from_model_on_disk validation of a candidate Anima LoRA where the state dict either lacks blocks.X.* Cosmos DiT keys entirely (e.g. a transformer_blocks/h--style naming from another DiT) or has Cosmos keys without lora/lora_A/lora_down style suffixes (e.g. a full Anima checkpoint probed as a LoRA).","commonSituations":"Installing an Anima full-model checkpoint through the LoRA config class by mistake; downloading a similarly-named LoRA trained for another Cosmos-variant model; key-renaming tools or ComfyUI exports that strip the standard suffixes; the file simply is not an Anima LoRA at all and auto-detection is just cycling through config classes.","solutions":["Confirm the file's role: if it is a full Anima checkpoint, install it as a main/checkpoint model, not a LoRA.","Dump keys and verify both the blocks.X.* pattern and a lora suffix; if suffixes were stripped, re-export with standard LoRA naming.","If it targets a different DiT, let the matching config class claim it (or choose the model type manually in the installer).","Update InvokeAI if the Anima/Cosmos export naming is newer than the installed heuristic table."],"exampleFix":"// before: full checkpoint hits the LoRA probe and raises\ninstaller.install_as_lora(path=\"anima_v1.safetensors\")  # NotAMatchError\n// after: verify Cosmos block keys + lora suffix first\nfrom safetensors import safe_open\nimport re\nwith safe_open(\"anima_v1.safetensors\", framework=\"pt\") as f:\n    ks = list(f.keys())\ncosmos = [k for k in ks if re.search(r\"blocks\\.\\d+\\.(mlp|adaln_modulation|cross_attn\\.)\", k)]\nhas_lora_suffix = any(k.endswith((\"lora_A\", \"lora_B\", \"lora_down\", \"lora_up\")) or \".lora_\" in k for k in ks)\nif cosmos and has_lora_suffix:\n    installer.install_as_lora(path=\"anima_v1.safetensors\")\nelse:\n    installer.install_as_checkpoint(path=\"anima_v1.safetensors\")","handlingStrategy":"validation","validationCode":"import re\nfrom safetensors import safe_open\n\ndef looks_like_anima_lora(path):\n    with safe_open(path, framework=\"pt\") as f:\n        ks = list(f.keys())\n    cosmos = any(re.search(r\"blocks\\.\\d+\\.(mlp|adaln_modulation|cross_attn\\.)\", k) for k in ks)\n    suffix = any(k.endswith((\"lora_A\", \"lora_B\", \"lora_down\", \"lora_up\")) or \".lora_\" in k for k in ks)\n    return cosmos and suffix\n\nassert looks_like_anima_lora(\"model.safetensors\"), \"not an Anima LoRA — likely a checkpoint or another format\"","typeGuard":"def is_anima_lora_state_dict(keys: list[str]) -> bool:\n    import re\n    cosmos = any(re.search(r\"blocks\\.\\d+\\.(mlp|adaln_modulation|cross_attn\\.)\", k) for k in keys)\n    suffix = any(k.endswith((\"lora_A\", \"lora_B\", \"lora_down\", \"lora_up\")) or \".lora_\" in k for k in keys)\n    return cosmos and suffix","tryCatchPattern":"try:\n    installer.install_as_lora(path=\"model.safetensors\")\nexcept NotAMatchError as e:\n    if \"Anima LoRA heuristics\" in str(e):\n        log.warning(\"not an Anima LoRA (%s); retrying as checkpoint/main model\", e)\n        installer.install_as_checkpoint(path=\"model.safetensors\")\n    else:\n        raise","preventionTips":["Determine whether the file is a LoRA or a full checkpoint before choosing the config class.","Scan keys for the blocks.X.* Cosmos pattern plus a lora suffix as a pre-install gate.","Use exports that keep standard LoRA suffixes; avoid key-renaming tools that strip them.","Keep InvokeAI updated if the Anima/Cosmos export tooling changed its naming scheme."],"tags":["invokeai","model-manager","lora","anima","not-a-match","model-install"],"backgroundTag":"lora-not-a-match","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}