{"record":{"id":"ff88e1e103d5989f","repo":"invoke-ai/InvokeAI","slug":"unexpected-keys-loading-sdnq-qwen3-text-encoder","errorCode":null,"errorMessage":"Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}","messagePattern":"Unexpected keys loading SDNQ Qwen3 text encoder: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/model_manager/load/model_loaders/z_image.py","lineNumber":638,"sourceCode":"        )\n\n    def _load_text_encoder(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:\n        from transformers import AutoConfig, Qwen3ForCausalLM\n\n        te_dir = resolve_submodel_path(config, SubModelType.TextEncoder, Path(config.path) / \"text_encoder\")\n        target_device = TorchDevice.choose_torch_device()\n        compute_dtype = TorchDevice.choose_bfloat16_safe_dtype(target_device)\n\n        te_config = AutoConfig.from_pretrained(te_dir, local_files_only=True)\n        with accelerate.init_empty_weights():\n            model = Qwen3ForCausalLM(te_config)\n\n        sd = sdnq_sd_loader(te_dir, compute_dtype=compute_dtype)\n        # Qwen3ForCausalLM may share lm_head.weight with model.embed_tokens.weight; missing keys\n        # for that tie are expected and handled by re-sharing post-load.\n        missing, unexpected = model.load_state_dict(sd, assign=True, strict=False)\n        if unexpected:\n            raise ValueError(f\"Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}\")\n        if missing and missing != [\"lm_head.weight\"]:\n            raise ValueError(f\"Unexpected missing keys loading SDNQ Qwen3 text encoder: {missing}\")\n        if missing == [\"lm_head.weight\"]:\n            model.lm_head.weight = model.model.embed_tokens.weight\n        return model\n\n    def _load_tokenizer(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:\n        tok_dir = resolve_submodel_path(config, SubModelType.Tokenizer, Path(config.path) / \"tokenizer\")\n        return AutoTokenizer.from_pretrained(tok_dir, local_files_only=True)\n\n    def _load_vae(self, config: Main_SDNQ_Diffusers_ZImage_Config) -> AnyModel:\n        from diffusers import AutoencoderKL\n\n        vae_dir = resolve_submodel_path(config, SubModelType.VAE, Path(config.path) / \"vae\")\n        return AutoencoderKL.from_pretrained(vae_dir, local_files_only=True)\n\n    def _load_from_singlefile(\n        self,","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/load/model_loaders/z_image.py#L620-L656","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the text_encoder/ folder actually contains SDNQ-quantized Qwen3 weights matching Qwen3ForCausalLM; re-export or re-download it.","Inspect the reported unexpected key names to identify the mismatch (prefixes, quant-metadata keys, renamed modules).","Upgrade/downgrade transformers and the SDNQ tooling so parameter naming matches the checkpoint's export version.","If keys are harmless quant-metadata, strip them before load_state_dict or update the loader's expected-key filter."],"exampleFix":"// before\nmodel.load_state_dict(sd, assign=True, strict=False)  # ValueError on unexpected keys\n// after\nsd = {k: v for k, v in sd.items() if k in dict(model.named_parameters()) or k in dict(model.named_buffers())}\nmissing, unexpected = model.load_state_dict(sd, assign=True, strict=False)\nif unexpected:\n    raise ValueError(f\"Unexpected keys loading SDNQ Qwen3 text encoder: {unexpected}\")","handlingStrategy":"validation","validationCode":"model_keys = set(model.state_dict().keys())\nextra = [k for k in sd if k not in model_keys]\nif extra:\n    raise ValueError(f\"checkpoint has keys unknown to Qwen3ForCausalLM: {extra[:5]}...\")","typeGuard":"def state_dict_matches_architecture(sd: dict, model) -> bool:\n    model_keys = set(model.state_dict().keys())\n    return all(k in model_keys for k in sd)","tryCatchPattern":"try:\n    te = loader._load_model(config, SubModelType.TextEncoder)\nexcept ValueError as e:\n    if \"Unexpected keys loading SDNQ Qwen3 text encoder\" in str(e):\n        te = reexport_or_redownload_text_encoder(config)  # fix weights, then retry\n        te = loader._load_model(config, SubModelType.TextEncoder)\n    else:\n        raise","preventionTips":["Keep the text_encoder folder from the same release/quantization run as the rest of the model.","Pin the transformers version used at quantization time.","Verify hashes of downloaded text_encoder files before first use.","Log unexpected key names to spot architecture drift early."],"tags":["python","state-dict","qwen3","sdnq","weight-loading"],"backgroundTag":"state-dict-key-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}