invoke-ai/InvokeAI · error · NotAMatchError
standalone Qwen3-VL encoder directory does not contain model
Error message
standalone Qwen3-VL encoder directory does not contain model weights
What it means
After confirming the config is a valid Qwen3-VL 4B config, from_model_on_disk verifies that the weights directory actually contains complete pretrained weights: a single model.safetensors or pytorch_model.bin, or a sharded index whose every referenced shard file exists and is inside the folder. If not, it throws this NotAMatchError because an encoder directory without usable weights cannot be registered.
Source
Thrown at invokeai/backend/model_manager/configs/qwen3_vl_encoder.py:149
"Qwen3VLModel",
"Qwen3VLForConditionalGeneration",
},
)
_validate_krea2_qwen3_vl_config(expected_config_path)
if config_path_nested.exists():
weights_path = mod.path / "text_encoder"
tokenizer_path = mod.path / "tokenizer"
else:
weights_path = mod.path
tokenizer_path = mod.path
has_weights = _has_complete_pretrained_weights(weights_path)
has_tokenizer = (tokenizer_path / "tokenizer.json").exists() or (
(tokenizer_path / "vocab.json").exists() and (tokenizer_path / "merges.txt").exists()
)
if not has_weights:
raise NotAMatchError("standalone Qwen3-VL encoder directory does not contain model weights")
if not has_tokenizer:
raise NotAMatchError("standalone Qwen3-VL encoder directory does not contain tokenizer files")
return cls(**override_fields)
def _is_qwen3_vl_encoder_state_dict(state_dict: dict[str | int, Any]) -> bool:
"""True for a single-file Qwen3-VL encoder: a Qwen3 text decoder PLUS a visual tower.
The visual tower (``visual.*`` / ``model.visual.*``) distinguishes Qwen3-VL from the text-only
``Qwen3Encoder`` (Z-Image / FLUX.2 Klein), which has ``model.layers.*`` but no visual tower.
"""
str_keys = [k for k in state_dict if isinstance(k, str)]
has_text_decoder = any(".layers." in k and ("model." in k or k.startswith("layers.")) for k in str_keys)
has_visual_tower = any(k.startswith(("visual.", "model.visual.")) or ".visual." in k for k in str_keys)
return has_text_decoder and has_visual_tower
View on GitHub (pinned to 0b6a024f2f)
Solutions
- Re-download the model weights completely; for sharded models ensure every file listed in model.safetensors.index.json is present in the same folder.
- Verify shard filenames in the index's weight_map match the files on disk exactly (no renaming or path prefixes).
- If you assembled the folder by hand, copy the weight files (model.safetensors or pytorch_model.bin) next to config.json.
- Use a resumable downloader (huggingface-cli download) to repair partial downloads, then rescan the folder in InvokeAI.
Example fix
// before: sharded index with missing shard models/qwen3vl-encoder/ config.json model.safetensors.index.json (shards missing) -> NotAMatchError // after models/qwen3vl-encoder/ config.json model.safetensors.index.json model-00001-of-00002.safetensors model-00002-of-00002.safetensors
Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
def has_complete_weights(model_dir: str) -> bool:
p = Path(model_dir) / "text_encoder"
if not p.is_dir():
p = Path(model_dir)
if (p / "model.safetensors").is_file() or (p / "pytorch_model.bin").is_file():
return True
for idx in ("model.safetensors.index.json", "pytorch_model.bin.index.json"):
ip = p / idx
if ip.is_file():
wm = json.loads(ip.read_text()).get("weight_map", {})
if not all((p / fn).is_file() for fn in wm.values()):
return False
return bool(wm)
return False Type guard
def weights_present(weights_dir) -> bool:
from pathlib import Path
p = Path(weights_dir)
return (p / "model.safetensors").is_file() or (p / "pytorch_model.bin").is_file() or (p / "model.safetensors.index.json").is_file() Try / catch
try:
cfg = Qwen3VLEncoder_Qwen3VLEncoder_Config.from_model_on_disk(mod, {})
except NotAMatchError as e:
if "does not contain model weights" in str(e):
logger.warning("%s has no complete weights; re-run huggingface-cli download", mod.path) Prevention
- Use resumable downloaders (huggingface-cli download / snapshot_download) instead of manual per-file fetches.
- For sharded models, verify every weight_map entry exists before importing.
- Do not delete large safetensors shards to free space without removing the model from InvokeAI.
- Keep shard files next to their index and unrenamed.
When it happens
Trigger: from_model_on_disk runs _has_complete_pretrained_weights on the weights path (text_encoder/ subfolder or directory root) and finds no model.safetensors/pytorch_model.bin and no valid complete sharded index - e.g. only an index json with missing shard files, or no weight files at all.
Common situations: Interrupted or partial HuggingFace download (index json present, shards missing), copying only config.json and tokenizer files, shards downloaded but renamed, shards placed outside the directory (absolute/escaping paths in weight_map), or storage cleanup deleting large safetensors shards.
Related errors
- unable to load config file: {config_path_nested} does not ex
- unrecognized token vector length {token_vector_length}
- model is not a FLUX.2 LoRA
- model does not match Z-Image LoRA heuristics
- model does not match Qwen Image LoRA heuristics
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/b1379ef4c9356a23.
Report an issue: GitHub.