invoke-ai/InvokeAI · warning · NotAMatchError
unable to read Qwen3 config.json: {e}
Error message
unable to read Qwen3 config.json: {e} What it means
During model identification, Qwen3Encoder config classes read the model's config.json to determine which Qwen3 variant (8B/4B/0.6B) the weights belong to. If the file cannot be parsed as JSON or cannot be opened on disk, _get_variant_from_config wraps the underlying OSError/JSONDecodeError in a NotAMatchError so the model-record store can skip this config and try the next candidate. It is a normal 'not this format' signal, not a crash of the library.
Source
Thrown at invokeai/backend/model_manager/configs/qwen3_encoder.py:374
continue
if quant_config.get("quant_method") == "sdnq":
raise NotAMatchError("folder is SDNQ-quantized; use Qwen3Encoder_SDNQ_Folder_Config")
if _has_sdnq_keys(mod.load_state_dict()):
raise NotAMatchError("state dict looks SDNQ-quantized; use Qwen3Encoder_SDNQ_Folder_Config")
@classmethod
def _get_variant_from_config(cls, config_path) -> Qwen3VariantType:
"""Get variant from config.json based on hidden_size, or raise NotAMatch if unknown."""
QWEN3_06B_HIDDEN_SIZE = 1024
QWEN3_4B_HIDDEN_SIZE = 2560
QWEN3_8B_HIDDEN_SIZE = 4096
try:
with open(config_path, "r", encoding="utf-8") as f:
config = json.load(f)
except (json.JSONDecodeError, OSError) as e:
raise NotAMatchError(f"unable to read Qwen3 config.json: {e}") from e
hidden_size = config.get("hidden_size")
if hidden_size == QWEN3_8B_HIDDEN_SIZE:
return Qwen3VariantType.Qwen3_8B
elif hidden_size == QWEN3_4B_HIDDEN_SIZE:
return Qwen3VariantType.Qwen3_4B
elif hidden_size == QWEN3_06B_HIDDEN_SIZE:
return Qwen3VariantType.Qwen3_06B
raise NotAMatchError(f"hidden_size {hidden_size} does not match a known Qwen3 variant")
class Qwen3Encoder_GGUF_Config(Checkpoint_Config_Base, Config_Base):
"""Configuration for GGUF-quantized Qwen3 Encoder models."""
base: Literal[BaseModelType.Any] = Field(default=BaseModelType.Any)
type: Literal[ModelType.Qwen3Encoder] = Field(default=ModelType.Qwen3Encoder)
format: Literal[ModelFormat.GGUFQuantized] = Field(default=ModelFormat.GGUFQuantized)
cpu_only: bool | None = Field(default=None, description="Whether this model should run on CPU only")View on GitHub (pinned to 0b6a024f2f)
Solutions
- Re-download the model (or just config.json) from the source repo so the file is complete and valid JSON.
- Validate the file: `python -c "import json;json.load(open('<path>/config.json'))"` and fix any syntax errors reported.
- Check file permissions/ownership on config.json and the parent directory (chmod u+r / chown).
- If the model is not actually a Qwen3 encoder, ignore the NotAMatchError — it is expected behavior and other config classes will claim the model.
- If the file is intentionally absent, ensure the model layout matches what InvokeAI expects (config.json present at the model root).
Example fix
// before (corrupt/truncated config.json)
{"architectures": ["Qwen3ForCausalLM"], "hidden_size": 4096
// after (complete valid JSON)
{"architectures": ["Qwen3ForCausalLM"], "hidden_size": 4096}
Defensive patterns
Strategy: validation
Validate before calling
import json, os
def qwen3_config_is_readable(model_dir):
p = os.path.join(model_dir, 'config.json')
if not os.path.isfile(p):
return False
try:
with open(p, 'r', encoding='utf-8') as f:
cfg = json.load(f)
except (json.JSONDecodeError, OSError):
return False
return isinstance(cfg.get('hidden_size'), int) Type guard
def has_valid_qwen3_config(cfg) -> bool:
return isinstance(cfg, dict) and isinstance(cfg.get('hidden_size'), int) Try / catch
from invokeai.backend.model_manager.configs.qwen3_encoder import Qwen3Encoder_Checkpoint_Config
try:
config = Qwen3Encoder_Checkpoint_Config.from_model_on_disk(mod, subtype)
except NotAMatchError as e:
logger.warning(f'Skipping {mod.path}: {e}') # expected for non-Qwen3 / corrupt config.json Prevention
- Always download models with a resumable tool (huggingface-cli/hf download) so config.json is never partial.
- Run `json.load()` on config.json as a pre-install sanity check.
- Never hand-edit config.json with trailing commas or comments.
- Check file read permissions before scanning large model directories.
When it happens
Trigger: Calling ModelManager install/scan (from_model_on_disk -> _get_variant_from_config) on a folder containing a config.json that is truncated, corrupted, mid-download, has invalid JSON syntax, or is unreadable due to file permissions/encoding, while the folder otherwise looks like a Qwen3 text-encoder model.
Common situations: Interrupted HuggingFace downloads leaving a partial config.json; manually edited config.json with a trailing comma or comment; symlink to a missing file; permission-denied file on shared/NFS mounts; a non-Qwen3 repo that happens to be probed by this config class.
Related errors
- state dict does not look like a Qwen3 model
- hidden_size {hidden_size} does not match a known Qwen3 varia
- state dict does not look like GGUF quantized
- Failed to remove image from board
- Failed to get intermediates
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/2049bdeea3cde9a4.
Report an issue: GitHub.