invoke-ai/InvokeAI · error · RuntimeError
PiD checkpoint has {len(not_strings)} keys that are not stri
Error message
PiD checkpoint has {len(not_strings)} keys that are not strings and so cannot name a PidNet parameter: {not_strings[:5]}(+ {len(not_strings) - 5} more) What it means
Before handing the state dict to torch, load_pid_decoder checks that every checkpoint key is a string, because nn.Module.load_state_dict would otherwise crash with an opaque AttributeError inside .startswith(). Non-string keys mean the .pth file unpickled to something malformed (e.g. a dict keyed by ints/objects), so it is rejected up front with a RuntimeError showing up to 5 offending keys. This makes a corrupt checkpoint fail with the same readable message style as other unusable checkpoints.
Source
Thrown at invokeai/backend/pid/decode.py:265
def load_pid_decoder(state_dict: dict[Any, Tensor], backbone: BaseModelType) -> PidNet:
"""Instantiate a PidNet for *backbone* and populate it with *state_dict*.
The state dict is expected to be the model-manager loader's output, i.e.
already stripped of the `net.` prefix used by NVIDIA's distill model
serialisation. The caller still owns dtype/device placement of the
returned net.
"""
net = build_pid_net(backbone)
# 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 = (View on GitHub (pinned to 0b6a024f2f)
Solutions
- Verify the file is a genuine PyTorch state dict (torch.load and inspect type(key) for key in sd)
- Re-export/re-save the checkpoint with torch.save(model.state_dict(), path)
- Ensure load_pid_decoder is pointed at the intended .pth file
Defensive patterns
Strategy: validation
Validate before calling
sd = torch.load(path, map_location="cpu")
bad = [k for k in sd if not isinstance(k, str)]
assert not bad, f"non-string keys: {bad[:5]}" Type guard
def is_valid_state_dict(sd) -> bool:
return isinstance(sd, dict) and all(isinstance(k, str) for k in sd) Try / catch
try:
net = load_pid_decoder(path, backbone=backbone)
except RuntimeError as e:
if "not strings" in str(e):
logger.error(f"Malformed checkpoint {path}: {e}")
raise Prevention
- Checksum downloads
- Sanity-check keys after torch.load
- Never hand-edit .pth files
When it happens
Trigger: Loading a PiD decoder checkpoint whose top-level state-dict keys are not all strings — e.g. a pickled dict with integer/None/object keys, or a non-state-dict object that happens to be dict-like.
Common situations: Corrupted or hand-crafted .pth files, checkpoints saved from non-PyTorch serialization, or loading the wrong file entirely (a pickled dataset/dict instead of a model).
Related errors
- Unexpected key: {k}
- missing keys after fp8 load: {missing[:10]}
- unable to determine base type from state dict
- unable to determine model variant from state dict
- state dict does not look like a main model
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/ec42d8a449818641.
Report an issue: GitHub.