{"record":{"id":"653e2082e48c3099","repo":"invoke-ai/InvokeAI","slug":"unexpected-missing-keys-loading-sdnq-qwen3-text-en","errorCode":null,"errorMessage":"Unexpected missing keys loading SDNQ Qwen3 text encoder: {missing}","messagePattern":"Unexpected missing 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":640,"sourceCode":"    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,\n        config: Main_SDNQ_ZImage_Config,\n    ) -> AnyModel:","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/load/model_loaders/z_image.py#L622-L658","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the reported missing-key names and re-download/re-export the text_encoder so all Qwen3 parameters are present.","Verify file integrity (sizes/hashes) of the SDNQ checkpoint — a partial file is the most common cause.","Align the transformers version with the one used at quantization time so parameter names match.","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."],"exampleFix":"// before\nmissing, unexpected = model.load_state_dict(sd, assign=True, strict=False)\nif missing and missing != [\"lm_head.weight\"]:\n    raise ValueError(...)  # fires on any other missing key\n// after\nprint(sorted(missing))  # diagnose which params are absent, then re-export/re-download the text_encoder\nassert not [k for k in missing if k != \"lm_head.weight\"], f\"checkpoint incomplete: {missing}\"","handlingStrategy":"validation","validationCode":"model_keys = set(model.state_dict().keys())\nmissing = [k for k in model_keys if k not in sd and k != \"lm_head.weight\"]\nif missing:\n    raise ValueError(f\"checkpoint is incomplete, missing: {missing[:5]}...\")","typeGuard":"def state_dict_is_complete(sd: dict, model, allowed_tied=(\"lm_head.weight\",)) -> bool:\n    model_keys = set(model.state_dict().keys())\n    return all(k in sd or k in allowed_tied for k in model_keys)","tryCatchPattern":"try:\n    te = loader._load_model(config, SubModelType.TextEncoder)\nexcept ValueError as e:\n    if \"Unexpected missing keys loading SDNQ Qwen3 text encoder\" in str(e):\n        redownload_text_encoder(config)  # incomplete/corrupt checkpoint\n        te = loader._load_model(config, SubModelType.TextEncoder)\n    else:\n        raise","preventionTips":["Verify download completeness (file sizes/hashes) for text_encoder weights.","Never hand-prune state dicts; re-quantize instead.","Keep transformers versions consistent between export and load.","Fail fast on incomplete downloads with a checksum step before registering the model."],"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"}