invoke-ai/InvokeAI · error · ValueError

Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected

Error message

Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}

What it means

When loading the SDNQ-quantized Qwen3 text encoder, load_state_dict(strict=False) reports keys in the checkpoint that do not match any Qwen3ForCausalLM parameter. Any unexpected key is treated as a fatal mismatch and raises this ValueError, because unexpected keys mean the weights file does not correspond to the expected Qwen3 architecture.

Source

Thrown at invokeai/backend/model_manager/load/model_loaders/z_image.py:638

        )

    def _load_text_encoder(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:
        from transformers import AutoConfig, Qwen3ForCausalLM

        te_dir = resolve_submodel_path(config, SubModelType.TextEncoder, Path(config.path) / "text_encoder")
        target_device = TorchDevice.choose_torch_device()
        compute_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device)

        te_config = AutoConfig.from_pretrained(te_dir, local_files_only=True)
        with accelerate.init_empty_weights():
            model = Qwen3ForCausalLM(te_config)

        sd = sdnq_sd_loader(te_dir, compute_dtype=compute_dtype)
        # Qwen3ForCausalLM may share lm_head.weight with model.embed_tokens.weight; missing keys
        # for that tie are expected and handled by re-sharing post-load.
        missing, unexpected = model.load_state_dict(sd, assign=True, strict=False)
        if unexpected:
            raise ValueError(f"Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}")
        if missing and missing != ["lm_head.weight"]:
            raise ValueError(f"Unexpected missing keys loading SDNQ Qwen3 text encoder: {missing}")
        if missing == ["lm_head.weight"]:
            model.lm_head.weight = model.model.embed_tokens.weight
        return model

    def _load_tokenizer(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:
        tok_dir = resolve_submodel_path(config, SubModelType.Tokenizer, Path(config.path) / "tokenizer")
        return AutoTokenizer.from_pretrained(tok_dir, local_files_only=True)

    def _load_vae(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:
        from diffusers import AutoencoderKL

        vae_dir = resolve_submodel_path(config, SubModelType.VAE, Path(config.path) / "vae")
        return AutoencoderKL.from_pretrained(vae_dir, local_files_only=True)

    def _load_from_singlefile(
        self,

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Verify the text_encoder/ folder actually contains SDNQ-quantized Qwen3 weights matching Qwen3ForCausalLM; re-export or re-download it.
  2. Inspect the reported unexpected key names to identify the mismatch (prefixes, quant-metadata keys, renamed modules).
  3. Upgrade/downgrade transformers and the SDNQ tooling so parameter naming matches the checkpoint's export version.
  4. If keys are harmless quant-metadata, strip them before load_state_dict or update the loader's expected-key filter.

Example fix

// before
model.load_state_dict(sd, assign=True, strict=False)  # ValueError on unexpected keys
// after
sd = {k: v for k, v in sd.items() if k in dict(model.named_parameters()) or k in dict(model.named_buffers())}
missing, unexpected = model.load_state_dict(sd, assign=True, strict=False)
if unexpected:
    raise ValueError(f"Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}")
Defensive patterns

Strategy: validation

Validate before calling

model_keys = set(model.state_dict().keys())
extra = [k for k in sd if k not in model_keys]
if extra:
    raise ValueError(f"checkpoint has keys unknown to Qwen3ForCausalLM: {extra[:5]}...")

Type guard

def state_dict_matches_architecture(sd: dict, model) -> bool:
    model_keys = set(model.state_dict().keys())
    return all(k in model_keys for k in sd)

Try / catch

try:
    te = loader._load_model(config, SubModelType.TextEncoder)
except ValueError as e:
    if "Unexpected keys loading SDNQ Qwen3 text encoder" in str(e):
        te = reexport_or_redownload_text_encoder(config)  # fix weights, then retry
        te = loader._load_model(config, SubModelType.TextEncoder)
    else:
        raise

Prevention

When it happens

Trigger: Loading a text_encoder subfolder whose SDNQ state dict contains keys absent from Qwen3ForCausalLM — wrong model in text_encoder/, an architecture change across Qwen3 revisions, extra buffers/quant metadata keys the loader doesn't strip, or a truncated/corrupted export.

Common situations: Mixing text-encoder folders from different model families into an SDNQ ZImagePipeline; a diffusers/transformers version changed parameter naming so checkpoint keys no longer match; hand-edited or repackaged SDNQ exports leaving stray keys.

Related errors


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