invoke-ai/InvokeAI · error · NotAMatchError

Krea-2 LoRA has an incomplete lora_A/B (or lora_down/up) wei

Error message

Krea-2 LoRA has an incomplete lora_A/B (or lora_down/up) weight pair

What it means

Immediately after the heuristic pair check, the Krea-2 LoRA config runs _lora_weight_keys_are_all_paired to reject files containing an ORPHANED LoRA half: at least one valid layer plus a dangling lora_A/lora_B/lora_down/lora_up with no counterpart. Such a file would pass the initial check but crash later during LoRA conversion, so it is rejected up front with this NotAMatchError.

Source

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

        cls._validate_looks_like_lora(mod)
        cls._validate_base(mod)
        return cls(**override_fields)

    @classmethod
    def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None:
        """Krea-2 LoRAs have keys like transformer.text_fusion.* / transformer.transformer_blocks.* with
        a lora_A/lora_B (or lora_down/lora_up) suffix. The text-fusion stage is unique to Krea-2."""
        state_dict = mod.load_state_dict()
        # Require a *complete* lora_A/B (or lora_down/up) pair, not merely any lora/dora suffix: a file with
        # only ``dora_scale`` and no A/B weights would pass a suffix check but fail later on missing weights.
        if not (_has_krea2_lora_keys(state_dict) and _has_complete_lora_pair(state_dict)):
            raise NotAMatchError(
                "model does not match Krea-2 LoRA heuristics (no complete lora_A/B or lora_down/up pair)"
            )
        # Reject a file with an orphaned LoRA half (a valid layer plus a dangling lora_A/B/down/up); it
        # would install here but fail later during LoRA conversion.
        if not _lora_weight_keys_are_all_paired(state_dict):
            raise NotAMatchError("Krea-2 LoRA has an incomplete lora_A/B (or lora_down/up) weight pair")

    @classmethod
    def _get_base_or_raise(cls, mod: ModelOnDisk) -> BaseModelType:
        if _has_krea2_lora_keys(mod.load_state_dict()):
            return BaseModelType.Krea2
        raise NotAMatchError("model does not look like a Krea-2 LoRA")


class LoRA_LyCORIS_Anima_Config(LoRA_LyCORIS_Config_Base, Config_Base):
    """Model config for Anima LoRA models in LyCORIS format."""

    base: Literal[BaseModelType.Anima] = Field(default=BaseModelType.Anima)

    @classmethod
    def _validate_looks_like_lora(cls, mod: ModelOnDisk) -> None:
        """Anima LoRAs use Kohya-style keys targeting Cosmos DiT blocks.

        Anima LoRAs have keys like:

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Re-download or re-export the LoRA; an orphaned half almost always means a corrupted or mis-merged file.
  2. Scan keys and find the layer(s) missing their sibling tensor (lora_A without lora_B, lora_down without lora_up), then remove the dangling keys or restore the missing tensor before installing.
  3. Re-merge the LoRA from its original training checkpoint so every layer is complete.
  4. If only one layer is broken, prune that layer entirely (the LoRA degrades gracefully) and reinstall.

Example fix

// before: orphaned half crashes conversion later
installer.install(path="krea2_lora.safetensors")
// after: detect and prune orphaned halves first
from safetensors import safe_open
with safe_open("krea2_lora.safetensors", framework="pt") as f:
    ks = set(f.keys())
for base in {k.rsplit(".", 1)[0] for k in ks if any(k.endswith(s) for s in ("lora_A", "lora_B", "lora_down", "lora_up"))}:
    pair = {f"{base}.lora_A", f"{base}.lora_B"} <= ks or {f"{base}.lora_down", f"{base}.lora_up"} <= ks
    assert pair, f"orphaned LoRA half at {base}"
Defensive patterns

Strategy: validation

Validate before calling

from safetensors import safe_open

def find_orphaned_lora_halves(path):
    with safe_open(path, framework="pt") as f:
        ks = set(f.keys())
    suffixes = ("lora_A", "lora_B", "lora_down", "lora_up")
    orphans = []
    for k in (k for k in ks if any(k.endswith(s) for s in suffixes)):
        base = k.rsplit(".", 1)[0]
        if not ({f"{base}.lora_A", f"{base}.lora_B"} <= ks or {f"{base}.lora_down", f"{base}.lora_up"} <= ks):
            orphans.append(base)
    return orphans

assert not find_orphaned_lora_halves("krea2_lora.safetensors"), "file contains orphaned LoRA halves"

Type guard

def lora_keys_all_paired(keys: set[str]) -> bool:
    suffixes = ("lora_A", "lora_B", "lora_down", "lora_up")
    for k in (k for k in keys if any(k.endswith(s) for s in suffixes)):
        base = k.rsplit(".", 1)[0]
        if not ({f"{base}.lora_A", f"{base}.lora_B"} <= keys or {f"{base}.lora_down", f"{base}.lora_up"} <= keys):
            return False
    return True

Try / catch

try:
    installer.install(path="krea2_lora.safetensors")
except NotAMatchError as e:
    if "incomplete lora_A/B" in str(e):
        log.error("orphaned LoRA half in file: %s", e)
        cleaned = strip_orphaned_halves("krea2_lora.safetensors")  # drop dangling keys or re-export
        installer.install(path=cleaned)
    else:
        raise

Prevention

When it happens

Trigger: from_model_on_disk validation where the state dict contains one or more lora_A/lora_B (or lora_down/lora_up) keys whose sibling tensor is absent — e.g. a layer with only lora_down and no lora_up.

Common situations: Partially written or interrupted download; hand-edited or pruned LoRA exports that dropped one tensor to save space; merging scripts that concatenated key sets from two LoRAs and dropped duplicates incorrectly; corrupted safetensors headers after a failed save.

Related errors


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