invoke-ai/InvokeAI · error · InvalidMatchError

PiD checkpoint has a malformed latent_proj: expected a 4D co

Error message

PiD checkpoint has a malformed latent_proj: expected a 4D conv weight with a 1x1 kernel, got {shape if shape is not None else 'a value with no shape'}

What it means

InvalidMatchError from _raise_if_discriminator_malformed (called during PiDDecoder_Checkpoint_Config_Base.from_model_on_disk): the checkpoint contains the key lq_proj.latent_proj.0.weight, but its shape is None, has the wrong rank, or its spatial kernel does not match the expected conv kernel from the contract (a 4D conv weight). This weight encodes both the architecture version (dim 0) and the backbone latent channels (dim 1), so a malformed tensor means the file cannot be identified or loaded reliably — and skipping the check would silently fall through to name-only matching followed by a load-time size mismatch.

Source

Thrown at invokeai/backend/model_manager/configs/pid_decoder.py:85

# `.pth` is free to supply keys that are not strings (see `strip_net_prefix`).
_Shapes = Mapping[Any, tuple[int, ...] | None]


def _raise_if_discriminator_malformed(shapes: _Shapes, contract: Mapping[str, tuple[int, ...]]) -> None:
    """Reject a checkpoint whose latent projection is present but is not a conv weight.

    Every read identification makes off this weight requires it to be a 4D conv, and each used to
    answer None when it was not — so a malformed tensor made the architecture check, the backbone
    check and the channel check all abstain at once, and the file fell through to name-only matching,
    which happily accepted it. Loading then failed on a size mismatch.

    Only reached when the weight is present: its *absence* is a truncation, which
    `_raise_if_pid_net_contract_unmet` diagnoses far better than a guess about the architecture.
    """
    shape = shapes[_LATENT_PROJ_KEY]
    expected = contract[_LATENT_PROJ_KEY]
    if shape is None or len(shape) != len(expected) or shape[2:] != expected[2:]:
        raise InvalidMatchError(
            f"PiD checkpoint has a malformed {_LATENT_PROJ_KEY}: expected a "
            f"{len(expected)}D conv weight with a {'x'.join(str(d) for d in expected[2:])} kernel, got "
            f"{shape if shape is not None else 'a value with no shape'}"
        )


def _raise_if_architecture_unsupported(shapes: _Shapes) -> None:
    """Reject a PiD decoder whose network shape `build_pid_net` cannot construct.

    Runs before the contract check so the diagnosis is the accurate one: a v1.5 checkpoint is intact,
    and judging it against the legacy contract would report it as a pile of missing and unexpected
    keys rather than as the newer architecture it is.
    """
    lq_hidden_dim = shapes[_LATENT_PROJ_KEY][0]  # type: ignore[index]  # rank checked above
    if lq_hidden_dim != _SUPPORTED_LQ_HIDDEN_DIM:
        raise InvalidMatchError(
            f"PiD decoder has lq_proj hidden dim {lq_hidden_dim}, but InvokeAI only supports the legacy "
            f"{_SUPPORTED_LQ_HIDDEN_DIM}-dim architecture (NVIDIA's v1.5 checkpoints are not yet supported)."

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Re-download the checkpoint from https://huggingface.co/nvidia/PiD and retry — corruption/truncation is the most common cause
  2. Verify the file is an official PiD release for your backbone (FLUX.1, FLUX.2, SD3, SDXL, Qwen-Image) rather than a modified export; unmodified official weights carry the 4D conv latent_proj
  3. Inspect the tensor (torch.load and print the shape of the lq_proj.latent_proj.0.weight tensor) to confirm rank/kernel before reporting; a v1.5 checkpoint instead triggers the 512-dim architecture error

Example fix

// before
# importing a partially-downloaded PiD checkpoint:
# shapes["lq_proj.latent_proj.0.weight"] -> None
// after
# huggingface-cli download nvidia/PiD res2k_sr4x_flux.pth --local-dir .  # fresh copy
# re-run model import with the verified file
Defensive patterns

Strategy: validation

Validate before calling

import torch
sd = torch.load(pid_pth, map_location='cpu')
w = next(v for k, v in sd.items() if 'lq_proj.latent_proj.0.weight' in str(k))
assert w.dim() == 4 and w.shape[2:] == (3, 3), f'latent_proj malformed: {tuple(w.shape)}'

Type guard

def has_wellformed_latent_proj(shapes: dict) -> bool:
    s = shapes.get('lq_proj.latent_proj.0.weight')
    return s is not None and len(s) == 4 and tuple(s[2:]) == (3, 3)

Try / catch

try:
    import_model(pid_pth)
except InvalidMatchError as e:
    if 'malformed' in str(e) and 'latent_proj' in str(e):
        print(f'{pid_pth.name} is corrupt or modified — re-download from nvidia/PiD')
    else:
        raise

Prevention

When it happens

Trigger: Importing a truncated/corrupted NVIDIA PiD .pth checkpoint where the lq_proj tensor was written incompletely (shape lost or wrong); loading a PiD-like checkpoint from a modified/converted pipeline where latent_proj was replaced by a non-conv module (different rank or kernel); an unrelated tensor stored under a key containing 'lq_proj'.

Common situations: Interrupted HuggingFace downloads of nvidia/PiD res2k* checkpoints; repacking tools that rewrite conv layers (fused/replaced projections) before export; older PiD versions with a different latent_proj layout.

Understand the failure class

Related errors


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