invoke-ai/InvokeAI · error · NotAMatchError

model does not look like a Qwen Image Edit LoRA

Error message

model does not look like a Qwen Image Edit LoRA

What it means

InvokeAI probes every incoming LoRA file with per-format config classes, each of which implements _get_base_or_raise to decide which base model the weights target. The Qwen Image Edit LoRA config returns BaseModelType.QwenImage only when the state dict has qwen-ie keys AND has no z-image, krea2, or flux keys; otherwise it raises NotAMatchError with this message. It is a heuristic key-sniffing rejection, not a corruption or I/O problem.

Source

Thrown at invokeai/backend/model_manager/configs/lora.py:884

        )
        has_z_image_keys = state_dict_has_any_keys_starting_with(state_dict, {"diffusion_model.layers."})
        has_krea2_keys = _has_krea2_lora_keys(state_dict)
        has_flux_keys = state_dict_has_any_keys_starting_with(
            state_dict,
            {
                "double_blocks.",
                "single_blocks.",
                "single_transformer_blocks.",
                "transformer.single_transformer_blocks.",
                "lora_unet_double_blocks_",
                "lora_unet_single_blocks_",
                "lora_unet_single_transformer_blocks_",
            },
        )

        if has_qwen_ie_keys and not has_z_image_keys and not has_krea2_keys and not has_flux_keys:
            return BaseModelType.QwenImage
        raise NotAMatchError("model does not look like a Qwen Image Edit LoRA")


def _has_krea2_lora_keys(state_dict: dict[str | int, Any]) -> bool:
    """True if the state dict targets Krea-2's distinctive modules.

    Covers both the diffusers naming (``text_fusion`` / ``time_mod_proj``) and the native/ComfyUI naming
    (``txtfusion``, or the gated attention ``attn.wq`` + ``attn.gate`` unique to Krea-2's single-stream
    blocks) so native-format LoRAs are recognized as Krea-2 rather than falling through to another base.
    """
    str_keys = [k for k in state_dict.keys() if isinstance(k, str)]
    if any(("text_fusion" in k or "txtfusion" in k or "time_mod_proj" in k) for k in str_keys):
        return True
    # Native gated attention identifies a transformer-only Krea-2 LoRA that lacks the text-fusion stage.
    return any(".attn.wq." in k for k in str_keys) and any(".attn.gate." in k for k in str_keys)


# Each LoRA weight half must be accompanied by its partner half. An orphaned half installs successfully
# but crashes later during LoRA conversion, so we reject it at identification time.

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Verify the LoRA was actually trained for Qwen Image Edit; check the source page or peek at state-dict key prefixes (safetensors.safe_open -> keys()).
  2. Inspect the file's keys for flux/z-image/krea2 markers that make the probe ambiguous; if present, the file belongs to another format's config class and should be installed as that type.
  3. Manually set the base model / config type in the model manager UI or API instead of relying on auto-probe.
  4. Update InvokeAI; key-heuristic tables are extended in newer releases to recognize more Qwen Image Edit LoRA packagings.

Example fix

// before: auto-probe of a Flux/qwen hybrid file raises
installer.install(path="mixed_lora.safetensors")
// after: pre-check keys and route manually
from safetensors import safe_open
with safe_open("mixed_lora.safetensors", framework="pt") as f:
    keys = list(f.keys())
has_qwen = any("lora_unet_single_transformer_blocks_" in k for k in keys)
has_flux = any("transformer." in k or "flux" in k.lower() for k in keys)
if has_qwen and not has_flux:
    installer.install(path="mixed_lora.safetensors")
else:
    installer.install(path="mixed_lora.safetensors", config=ModelVariant(flux_lora_config))
Defensive patterns

Strategy: validation

Validate before calling

from safetensors import safe_open

def probe_qwen_ie_lora(path):
    with safe_open(path, framework="pt") as f:
        ks = list(f.keys())
    has_qwen = any("lora_unet_single_transformer_blocks_" in k for k in ks)
    has_z_image = any("z_image" in k.lower() for k in ks)
    has_krea2 = any("text_fusion" in k or "time_mod_proj" in k for k in ks)
    has_flux = any("double_blocks" in k or "single_blocks" in k for k in ks)
    return has_qwen and not (has_z_image or has_krea2 or has_flux)

assert probe_qwen_ie_lora("model.safetensors"), "file will be rejected as a Qwen Image Edit LoRA"

Type guard

def is_qwen_ie_lora_state_dict(keys: list[str]) -> bool:
    has_qwen = any("lora_unet_single_transformer_blocks_" in k for k in keys)
    other = any(s in k.lower() for k in keys for s in ("z_image", "text_fusion", "time_mod_proj", "double_blocks", "single_blocks"))
    return has_qwen and not other

Try / catch

from invokeai.backend.model_manager.configs.lora import NotAMatchError
try:
    installer.install(path="model.safetensors")
except NotAMatchError as e:
    if "Qwen Image Edit LoRA" in str(e):
        log.warning("not a Qwen IE LoRA: %s — inspect keys and pick the right base", e)
        installer.install(path="model.safetensors", base=detect_base_manually("model.safetensors"))
    else:
        raise

Prevention

When it happens

Trigger: Installing a LoRA via the model manager (from_model_on_disk -> _validate_base -> _get_base_or_raise) whose state dict either lacks the distinctive lora_unet_single_transformer_blocks_-style qwen-ie key prefixes, or has them alongside keys that also match z-image/krea2/flux heuristics (the guard `has_qwen_ie_keys and not has_z_image_keys and not has_krea2_keys and not has_flux_keys` fails).

Common situations: Downloading a LoRA trained for a different DiT (Flux, Z-Image, Krea-2) and pointing InvokeAI at it expecting auto-detection; multi-base merged/transition LoRAs whose key set overlaps several formats; renamed/re-packed files where the qwen-ie key prefixes were stripped; a newer InvokeAI key-naming scheme not covered by the installed version's heuristics.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/542d916c6093c2e1. Report an issue: GitHub.