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

  1. Use an XLabs-format IP-Adapter Flux checkpoint whose keys all start with 'ip_adapter_proj_model.' or 'double_blocks.'.
  2. Convert/strip foreign prefixes before calling, e.g. map diffusers keys to the XLabs naming scheme.
  3. Print sorted(state_dict.keys())[:10] to identify the unexpected prefix and adjust key-mapping code accordingly.
  4. 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

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


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