invoke-ai/InvokeAI · error · ValueError
Unexpected key: {k}
Error message
Unexpected key: {k} What it means
load_xlabs_state_dict partitions an XLabs IP-Adapter checkpoint into an image-projection dict (keys starting with 'ip_adapter_proj_model.') and a double-blocks dict (keys starting with 'double_blocks.'), loading each into the corresponding submodules. Any key with another prefix cannot belong to an XLabs Flux IP-Adapter checkpoint (e.g. a diffusers-format or CLIP-vision key), so it raises instead of silently dropping weights.
Source
Thrown at invokeai/backend/flux/ip_adapter/xlabs_ip_adapter_flux.py:62
)
self.ip_adapter_double_blocks = IPAdapterDoubleBlocks(
num_double_blocks=params.num_double_blocks, context_dim=params.context_dim, hidden_dim=params.hidden_dim
)
def load_xlabs_state_dict(self, state_dict: dict[str, torch.Tensor], assign: bool = False):
"""We need this custom function to load state dicts rather than using .load_state_dict(...) because the model
structure does not match the state_dict structure.
"""
# Split the state_dict into the image projection model and the double blocks.
image_proj_sd: dict[str, torch.Tensor] = {}
double_blocks_sd: dict[str, torch.Tensor] = {}
for k, v in state_dict.items():
if k.startswith("ip_adapter_proj_model."):
image_proj_sd[k] = v
elif k.startswith("double_blocks."):
double_blocks_sd[k] = v
else:
raise ValueError(f"Unexpected key: {k}")
# Initialize the image projection model.
image_proj_sd = {k.replace("ip_adapter_proj_model.", ""): v for k, v in image_proj_sd.items()}
self.image_proj.load_state_dict(image_proj_sd, assign=assign)
# Initialize the double blocks.
double_blocks_sd = {k.replace("processor.", ""): v for k, v in double_blocks_sd.items()}
self.ip_adapter_double_blocks.load_state_dict(double_blocks_sd, assign=assign)
View on GitHub (pinned to 0b6a024f2f)
Solutions
- Use an XLabs-format IP-Adapter Flux checkpoint whose keys all start with 'ip_adapter_proj_model.' or 'double_blocks.'.
- Convert/strip foreign prefixes before calling, e.g. map diffusers keys to the XLabs naming scheme.
- Print sorted(state_dict.keys())[:10] to identify the unexpected prefix and adjust key-mapping code accordingly.
- If intentional extra keys are present, filter them out before passing: sd = {k:v for k,v in sd.items() if k.startswith(('ip_adapter_proj_model.','double_blocks.'))}
Example fix
// before
model.load_xlabs_state_dict(state_dict, assign=True) # state_dict has 'image_proj.xxx' keys
// after
renamed = {k.replace("image_proj.", "ip_adapter_proj_model."): v for k, v in state_dict.items()}
model.load_xlabs_state_dict(renamed, assign=True) Defensive patterns
Strategy: validation
Validate before calling
bad = [k for k in state_dict if not k.startswith(("ip_adapter_proj_model.", "double_blocks."))]
if bad:
raise ValueError(f"non-XLabs keys present: {bad[:5]} ...; convert the checkpoint first") Type guard
def is_xlabs_ip_adapter_state_dict(sd: dict) -> bool:
return all(k.startswith(("ip_adapter_proj_model.", "double_blocks.")) for k in sd) Try / catch
try:
model.load_xlabs_state_dict(state_dict, assign=assign)
except ValueError as e:
if "Unexpected key" in str(e):
raise RuntimeError(f"checkpoint is not XLabs-format; offending keys: "
f"{[k for k in state_dict if not k.startswith(('ip_adapter_proj_model.','double_blocks.'))][:5]}") from e
raise Prevention
- Confirm the checkpoint is the XLabs (not diffusers) IP-Adapter Flux format before loading.
- Preview key prefixes with itertools.islice(sorted(state_dict), 5) when integrating new checkpoints.
- Keep a key-mapping/convert step for foreign formats and filter out irrelevant tensors before load.
When it happens
Trigger: Calling load_xlabs_state_dict with a state_dict containing keys outside the two expected prefixes — e.g. loading a diffusers IP-Adapter checkpoint (keys like 'image_proj.', 'ip_adapter.'), a transformer-suffixed key, or an unrelated tensor accidentally merged in.
Common situations: Pointing the loader at the wrong checkpoint file (diffusers-format XLabs adapter vs InvokeAI-format); checkpoint saved with extra wrapper prefixes; mixing adapter formats across versions.
Related errors
- PiD checkpoint has unexpected keys not present in PidNet: {u
- missing keys after fp8 load: {missing[:10]}
- unable to determine cross attention dimension: {e}
- unable to determine base type from state dict
- unable to determine model variant from state dict
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/733468148de0efc9.
Report an issue: GitHub.