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

  1. Re-download the model (or just config.json) from the source repo so the file is complete and valid JSON.
  2. Validate the file: `python -c "import json;json.load(open('<path>/config.json'))"` and fix any syntax errors reported.
  3. Check file permissions/ownership on config.json and the parent directory (chmod u+r / chown).
  4. If the model is not actually a Qwen3 encoder, ignore the NotAMatchError — it is expected behavior and other config classes will claim the model.
  5. 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

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


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/2049bdeea3cde9a4. Report an issue: GitHub.