invoke-ai/InvokeAI · error · RuntimeError

PiD checkpoint has unexpected keys not present in PidNet

Error message

PiD checkpoint has unexpected keys not present in PidNet: {unexpected[:5]}

What it means

load_pid_decoder loads with strict=False so missing and unexpected keys can be reported separately; both are fatal. If the checkpoint contains keys that do not exist in the constructed PidNet (architecture mismatch, wrong backbone, extra prefixes, or a foreign checkpoint), it raises RuntimeError listing up to 5 unexpected keys. Loading is refused because silently ignoring extra keys usually means the rest of the weights do not correspond to this architecture either.

Solutions

  1. Verify the checkpoint actually belongs to the PiD decoder for the given backbone
  2. Re-run strip_net_prefix / strip any 'module.' or wrapper prefixes from the checkpoint keys before loading
  3. Match the backbone argument to the checkpoint's true architecture
  4. Regenerate/download the correct checkpoint

Example fix

// before
net = load_pid_decoder(ckpt, backbone="pid_xl")  # ckpt is a base PixDiT_T2I
// after
net = load_pid_decoder(ckpt_pid_decoder, backbone="pid_xl")
Defensive patterns

Strategy: validation

Validate before calling

sd = torch.load(path, map_location="cpu")
extra = set(sd) - set(build_pid_net(backbone).state_dict())
assert not extra, f"unexpected keys: {sorted(extra)[:5]}"

Try / catch

try:
    net = load_pid_decoder(path, backbone=backbone)
except RuntimeError as e:
    if "unexpected keys" in str(e):
        logger.error(f"Checkpoint mismatch: {e}")
    raise

Prevention

When it happens

Trigger: Calling load_pid_decoder with a checkpoint whose keys don't match PidNet: wrong backbone argument, a checkpoint from a different architecture (e.g. base PixDiT_T2I with extra modules), or keys saved under a different naming scheme.

Common situations: Pointing a PiD decoder loader at an unrelated diffusion checkpoint, renaming modules between library versions, or mixing checkpoints across model variants.

Related errors


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

Appendix: source

Thrown at invokeai/backend/pid/decode.py:277

    # A `.pth` unpickles to whatever it contains, and a bare (un-prefixed) checkpoint reaches here
    # with its keys untouched — see `strip_net_prefix`. `nn.Module.load_state_dict` calls
    # `.startswith()` on every key, so a non-string one raises AttributeError from inside torch
    # before any of the reporting below runs. Reject it here instead, so a malformed checkpoint gets
    # the same kind of message as every other unusable one.
    if not_strings := sorted((k for k in state_dict if not isinstance(k, str)), key=str):
        raise RuntimeError(
            f"PiD checkpoint has {len(not_strings)} keys that are not strings and so cannot name a "
            f"PidNet parameter: {not_strings[:5]}"
            + (f" (+ {len(not_strings) - 5} more)" if len(not_strings) > 5 else "")
        )

    # strict=False so we can report missing and unexpected keys separately; both are fatal. The model
    # cache builds loaders under `skip_torch_weight_init()`, which no-ops every `reset_parameters()`,
    # so a key the checkpoint does not supply is left as uninitialised memory rather than a sane
    # default — a partial checkpoint would decode to garbage / NaNs instead of failing.
    missing, unexpected = net.load_state_dict(state_dict, strict=False)
    if unexpected:
        raise RuntimeError(
            f"PiD checkpoint has unexpected keys not present in PidNet: {unexpected[:5]}"
            + (f" (+ {len(unexpected) - 5} more)" if len(unexpected) > 5 else "")
        )
    if missing:
        lq = [k for k in missing if k.startswith("lq_proj.")]
        detail = (
            " (the LQ projection is incomplete — this looks like a base PixDiT_T2I checkpoint rather than a "
            "PiD super-resolution decoder)"
            if lq and len(lq) == len(missing)
            else ""
        )
        raise RuntimeError(
            f"PiD checkpoint is missing {len(missing)} keys required by PidNet{detail}: {missing[:5]}"
            + (f" (+ {len(missing) - 5} more)" if len(missing) > 5 else "")
        )
    return net

View on GitHub (pinned to 0b6a024f2f)