invoke-ai/InvokeAI · error · ValueError

Unexpected missing keys loading SDNQ Qwen3 text encoder: {mi

Error message

Unexpected missing keys loading SDNQ Qwen3 text encoder: {missing}

What it means

After loading the SDNQ Qwen3 text encoder, missing keys are tolerated only for lm_head.weight, which may be tied to model.embed_tokens.weight and re-shared after load. Any other set of missing keys raises this ValueError, indicating the checkpoint lacks required Qwen3 weights.

Source

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

    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,
        config: Main_SDNQ_ZImage_Config,
    ) -> AnyModel:

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Read the reported missing-key names and re-download/re-export the text_encoder so all Qwen3 parameters are present.
  2. Verify file integrity (sizes/hashes) of the SDNQ checkpoint — a partial file is the most common cause.
  3. Align the transformers version with the one used at quantization time so parameter names match.
  4. If a legitimately tied weight is reported, extend the loader's expected-tied-keys handling (like the existing lm_head.weight case) rather than loosening strict=False.

Example fix

// before
missing, unexpected = model.load_state_dict(sd, assign=True, strict=False)
if missing and missing != ["lm_head.weight"]:
    raise ValueError(...)  # fires on any other missing key
// after
print(sorted(missing))  # diagnose which params are absent, then re-export/re-download the text_encoder
assert not [k for k in missing if k != "lm_head.weight"], f"checkpoint incomplete: {missing}"
Defensive patterns

Strategy: validation

Validate before calling

model_keys = set(model.state_dict().keys())
missing = [k for k in model_keys if k not in sd and k != "lm_head.weight"]
if missing:
    raise ValueError(f"checkpoint is incomplete, missing: {missing[:5]}...")

Type guard

def state_dict_is_complete(sd: dict, model, allowed_tied=("lm_head.weight",)) -> bool:
    model_keys = set(model.state_dict().keys())
    return all(k in sd or k in allowed_tied for k in model_keys)

Try / catch

try:
    te = loader._load_model(config, SubModelType.TextEncoder)
except ValueError as e:
    if "Unexpected missing keys loading SDNQ Qwen3 text encoder" in str(e):
        redownload_text_encoder(config)  # incomplete/corrupt checkpoint
        te = loader._load_model(config, SubModelType.TextEncoder)
    else:
        raise

Prevention

When it happens

Trigger: The SDNQ state dict is missing parameters of Qwen3ForCausalLM other than lm_head.weight — partial export, pruned/truncated checkpoint, or key renaming from a transformers version change — so `missing` is non-empty and not exactly ['lm_head.weight'] at z_image.py:640.

Common situations: Incomplete download of the text_encoder folder; an export script dropped layers or quant blocks; a transformers upgrade renamed modules so keys no longer line up; corruption during SDNQ quantization.

Related errors


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