invoke-ai/InvokeAI · error · NotAMatchError

model does not match Z-Image LoRA heuristics

Error message

model does not match Z-Image LoRA heuristics

What it means

NotAMatchError raised by LoRA_LyCORIS_ZImage_Config._validate_looks_like_lora when the file neither matches the Z-Image Kohya LoRA detector (is_state_dict_likely_z_image_kohya_lora) nor has both Z-Image-style key prefixes (diffusion_model.layers., diffusion_model.context_refiner., diffusion_model.noise_refiner., transformer.layers., base_model.model.transformer.layers.) and LoRA weight suffixes (lora_A/lora_B/lora_down/lora_up/dora_scale). The config class requires both signals to claim a file as a Z-Image LoRA.

Source

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

            },
        )

        # Also check for LoRA weight suffixes (various formats)
        has_lora_suffix = state_dict_has_any_keys_ending_with(
            state_dict,
            {
                "lora_A.weight",
                "lora_B.weight",
                "lora_down.weight",
                "lora_up.weight",
                "dora_scale",
            },
        )

        if has_z_image_lora_keys and has_lora_suffix:
            return

        raise NotAMatchError("model does not match Z-Image LoRA heuristics")

    @classmethod
    def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType:
        """Z-Image LoRAs are identified by their diffusion_model.layers structure.

        Z-Image uses S3-DiT architecture with layer names like:
        - diffusion_model.layers.0.attention.to_k.lora_A.weight
        - diffusion_model.layers.0.feed_forward.w1.lora_A.weight
        - lora_unet__layers_0_attention_to_k.lora_down.weight (Kohya format)
        """
        from invokeai.backend.patches.lora_conversions.z_image_lora_conversion_utils import (
            is_state_dict_likely_z_image_kohya_lora,
        )

        state_dict = mod.load_state_dict()

        # Check for Kohya format
        if is_state_dict_likely_z_image_kohya_lora(state_dict):

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Confirm the file is actually a Z-Image LoRA; if it is for another base (Flux/Qwen/etc.), no action needed — another config should match it.
  2. Update InvokeAI — key-pattern heuristics for Z-Image trainers expand over time.
  3. Re-export the LoRA in Kohya format (lora_unet__layers_X_attention_to_k.lora_down.weight naming) or diffusers PEFT format so it matches known patterns.
  4. If keys use a variant prefix, rename keys in the state dict to one of the recognized prefixes (diffusion_model.layers., transformer.layers., etc.) before import.
  5. Use explicit base-model override fields at install time to bypass heuristic matching.

Example fix

// before: Z-Image LoRA with custom prefix 'net.layers.0.attn.to_k.lora_A.weight'
// after: rewrite keys to the recognized S3-DiT pattern
sd = {k.replace("net.layers.", "diffusion_model.layers."): v for k, v in sd.items()}
save_file(sd, "model.safetensors")
Defensive patterns

Strategy: validation

Validate before calling

from invokeai.backend.patches.lora_conversions.z_image_lora_conversion_utils import is_state_dict_likely_z_image_kohya_lora

sd = load_file("model.safetensors")
prefixes = ("diffusion_model.layers.", "diffusion_model.context_refiner.",
            "diffusion_model.noise_refiner.", "transformer.layers.",
            "base_model.model.transformer.layers.")
suffixes = ("lora_A.weight", "lora_B.weight", "lora_down.weight", "lora_up.weight", "dora_scale")
ok = is_state_dict_likely_z_image_kohya_lora(sd) or (
    any(k.startswith(prefixes) for k in sd) and any(k.endswith(suffixes) for k in sd)
)
if not ok:
    print("Not a recognizable Z-Image LoRA")

Type guard

def is_z_image_lora_state_dict(state_dict: dict) -> bool:
    prefixes = ("diffusion_model.layers.", "transformer.layers.", "base_model.model.transformer.layers.")
    suffixes = ("lora_A.weight", "lora_B.weight", "lora_down.weight", "lora_up.weight", "dora_scale")
    return any(k.startswith(prefixes) for k in state_dict) and any(k.endswith(suffixes) for k in state_dict)

Try / catch

try:
    config = LoRA_LyCORIS_ZImage_Config.from_model_on_disk(mod, {})
except NotAMatchError as e:
    logger.warning("Not a Z-Image LoRA (%s); trying other LoRA configs", e)
    config = LoRA_LyCORIS_Config_Base.from_model_on_disk(mod, {})

Prevention

When it happens

Trigger: from_model_on_disk probes a candidate against the Z-Image LyCORIS config and the state dict lacks the diffusion_model.layers.X structure (Z-Image S3-DiT) or lacks any recognizable LoRA weight suffix — e.g. a non-LoRA checkpoint, or a LoRA for another DiT model whose keys don't start with the expected prefixes.

Common situations: Scanning a regular diffusion checkpoint that happens to contain LoRA-ish keys, importing a LoRA for a similar architecture (Flux, Qwen-Image, Chroma) that routes through the Z-Image validator, or a Z-Image LoRA saved with fully custom key names by an unlisted trainer.

Related errors


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