{"record":{"id":"6049a36d95dbac57","repo":"invoke-ai/InvokeAI","slug":"state-dict-bundles-a-qwen-vl-visual-tower-this-is","errorCode":null,"errorMessage":"state dict bundles a Qwen-VL visual tower; this is a Qwen-VL encoder, not a text-only Qwen3 encoder","messagePattern":"state dict bundles a Qwen-VL visual tower; this is a Qwen-VL encoder, not a text-only Qwen3 encoder","errorType":"exception","errorClass":"NotAMatchError","httpStatus":null,"severity":"warning","filePath":"invokeai/backend/model_manager/configs/qwen3_encoder.py","lineNumber":249,"sourceCode":"        state_dict = mod.load_state_dict()\n        if not _has_qwen3_keys(state_dict):\n            raise NotAMatchError(\"state dict does not look like a Qwen3 model\")\n        # Reject T5 encoders: they share the token_embd.weight key with Qwen3 GGUFs but use the ``enc.``\n        # block prefix, and must be classified as T5Encoder (Qwen3 encoders never have ``enc.blk.*`` keys).\n        if _has_t5_encoder_keys(state_dict):\n            raise NotAMatchError(\"state dict looks like a T5 encoder (has 'enc.blk.*' keys), not a Qwen3 encoder\")\n        # Reject Gemma-2/3 encoders: their GGUFs also carry token_embd.weight + blk.* keys but use\n        # post-attention / post-feedforward norms a Qwen3 encoder never has; they must be classified as\n        # Gemma2Encoder (otherwise a Gemma GGUF matches both configs and can be re-identified wrongly).\n        if _has_gemma2_keys(state_dict):\n            raise NotAMatchError(\n                \"state dict looks like a Gemma-2 encoder (has post_attention_norm/post_ffw_norm keys), \"\n                \"not a Qwen3 encoder\"\n            )\n        # Reject Qwen2.5-VL / Qwen2-VL encoders: they carry a visual tower and must be\n        # classified as QwenVLEncoder (text-only Qwen3 encoders never have one).\n        if _has_qwen_vl_visual_tower(state_dict):\n            raise NotAMatchError(\n                \"state dict bundles a Qwen-VL visual tower; this is a Qwen-VL encoder, not a text-only Qwen3 encoder\"\n            )\n\n    @classmethod\n    def _validate_does_not_look_like_gguf_quantized(cls, mod: ModelOnDisk) -> None:\n        has_ggml = _has_ggml_tensors(mod.load_state_dict())\n        if has_ggml:\n            raise NotAMatchError(\"state dict looks like GGUF quantized\")\n\n\n# Transformers architectures the unquantized Qwen3 encoder config accepts.\n_QWEN3_ENCODER_ARCHITECTURES = {\n    \"Qwen2VLForConditionalGeneration\",\n    \"Qwen2ForCausalLM\",\n    \"Qwen3ForCausalLM\",\n}\n\n# Architectures the SDNQ Qwen encoder loaders can actually instantiate. Both the standalone","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/model_manager/configs/qwen3_encoder.py#L231-L267","documentation":"NotAMatchError raised by Qwen3Encoder._validate_looks_like_qwen3_model (qwen3_encoder.py:249). The state dict includes a Qwen-VL visual tower, meaning it is a multimodal Qwen2-VL / Qwen2.5-VL encoder, not a text-only Qwen3 encoder. The config raises so QwenVLEncoder claims the model; text-only Qwen3 encoders never bundle visual weights.","triggerScenarios":"from_model_on_disk identification of a Qwen2.5-VL/Qwen2-VL model whose state dict contains visual-tower tensors (detected by _has_qwen_vl_visual_tower) while the Qwen3Encoder config probes it.","commonSituations":"Downloading a full Qwen2.5-VL checkpoint and pointing InvokeAI's scanner at it expecting a Qwen3 text encoder; confusion between Qwen2-VL and Qwen3 model repos on HuggingFace; using a VL model where a text-only encoder is required by a pipeline (e.g. Z-Image).","solutions":["Use a text-only Qwen3 (or Qwen2) text encoder checkpoint instead of the VL variant if your pipeline needs a Qwen3Encoder.","Let identification continue so QwenVLEncoder matches, if you actually want the VL model.","Extract only the text encoder weights into a text_encoder/ subfolder if you only need the text side of the VL model.","Check the HuggingFace repo name: 'Qwen2.5-VL*'/'Qwen2-VL*' is multimodal; 'Qwen3-*' text encoders have no visual tower."],"exampleFix":"// before\nrepo = 'Qwen/Qwen2.5-VL-7B-Instruct'  // has visual tower\n// after\nrepo = 'Qwen/Qwen3-4B' (text-only encoder weights in text_encoder/)","handlingStrategy":"validation","validationCode":"import json\ndef is_qwen_vl_checkpoint(path) -> bool:\n    cfg = json.loads((path / 'config.json').read_text())\n    return cfg.get('architectures', [''])[0].endswith('ForConditionalGeneration') and 'VL' in cfg.get('model_type', '')","typeGuard":"def has_visual_tower(state_dict: dict) -> bool:\n    return any(k.startswith('visual.') or 'visual_tower' in k or k.startswith('model.visual') for k in state_dict)  # if True, it is Qwen-VL, not text-only Qwen3","tryCatchPattern":"try:\n    register_model(path, model_type='Qwen3Encoder')\nexcept NotAMatchError:\n    register_model(path, model_type='QwenVLEncoder')  # or use a text-only Qwen3 checkpoint","preventionTips":["Prefer text-only Qwen3 repos (no 'VL' in the name) for encoder use in Z-Image/FLUX.2 pipelines.","Check the repo's config.json model_type before download.","Extract only text-encoder weights if you must reuse a VL checkpoint."],"tags":["model-identification","state-dict","qwen3","qwen-vl"],"backgroundTag":"model-not-a-match","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}