invoke-ai/InvokeAI · info · NotAMatchError

directory looks like a full diffusers pipeline (has model_in

Error message

directory looks like a full diffusers pipeline (has model_index.json or transformer folder), not a standalone Qwen3 encoder

What it means

NotAMatchError raised in Qwen3Encoder_Qwen3Encoder_Config.from_model_on_disk (qwen3_encoder.py:300). The scanned directory is a full diffusers pipeline (it has model_index.json at root or a transformer/ subfolder), so it must be registered as a main pipeline model, not as a standalone Qwen3 text encoder. The guard prevents the Qwen3Encoder config from claiming whole pipelines.

Source

Thrown at invokeai/backend/model_manager/configs/qwen3_encoder.py:300

    base: Literal[BaseModelType.Any] = Field(default=BaseModelType.Any)
    type: Literal[ModelType.Qwen3Encoder] = Field(default=ModelType.Qwen3Encoder)
    format: Literal[ModelFormat.Qwen3Encoder] = Field(default=ModelFormat.Qwen3Encoder)
    cpu_only: bool | None = Field(default=None, description="Whether this model should run on CPU only")
    variant: Qwen3VariantType = Field(description="Qwen3 model size variant (4B or 8B)")

    @classmethod
    def from_model_on_disk(cls, mod: ModelOnDisk, override_fields: dict[str, Any]) -> Self:
        raise_if_not_dir(mod)

        raise_for_override_fields(cls, override_fields)

        # Exclude full pipeline models - these should be matched as main models, not just Qwen3 encoders.
        # Full pipelines have model_index.json at root (diffusers format) or a transformer subfolder.
        model_index_path = mod.path / "model_index.json"
        transformer_path = mod.path / "transformer"
        if model_index_path.exists() or transformer_path.exists():
            raise NotAMatchError(
                "directory looks like a full diffusers pipeline (has model_index.json or transformer folder), "
                "not a standalone Qwen3 encoder"
            )

        # Check for text_encoder config - support both:
        # 1. Full model structure: model_root/text_encoder/config.json
        # 2. Standalone text_encoder download: model_root/config.json (when text_encoder subfolder is downloaded separately)
        config_path_nested = mod.path / "text_encoder" / "config.json"
        config_path_direct = mod.path / "config.json"

        if config_path_nested.exists():
            expected_config_path = config_path_nested
        elif config_path_direct.exists():
            # Standalone text_encoder downloads do not bundle tokenizer files. If we see tokenizer files at the
            # root next to config.json, this is a complete causal LM (TextLLM), not a Qwen3 encoder subfolder.
            tokenizer_files = ("tokenizer.json", "tokenizer.model", "tokenizer_config.json")
            if any((mod.path / f).exists() for f in tokenizer_files):
                raise NotAMatchError(

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Install the directory as a main pipeline model — InvokeAI should match it with the appropriate pipeline config.
  2. If you only need the encoder, download just the text_encoder/ subfolder into its own directory and scan that.
  3. Move the full pipeline out of the folder being scanned as an encoder candidate.
  4. If you believe this is a false positive, rename/remove a stray model_index.json or transformer/ dir that leaked into the encoder folder.

Example fix

// before
models/z-image/  // full pipeline: model_index.json + transformer/ + text_encoder/
// after
models/z-image/ installed as pipeline; models/z-image-text-encoder/ containing only text_encoder/ contents
Defensive patterns

Strategy: validation

Validate before calling

def is_full_pipeline(path) -> bool:
    return (path / 'model_index.json').exists() or (path / 'transformer').is_dir()  # install as main pipeline model

Type guard

def is_standalone_encoder_dir(path) -> bool:
    return not (path / 'model_index.json').exists() and not (path / 'transformer').exists() and ((path / 'text_encoder' / 'config.json').exists() or (path / 'config.json').exists())

Try / catch

if is_full_pipeline(model_dir):
    install_as_pipeline(model_dir)
else:
    try:
        install_as_encoder(model_dir)
    except NotAMatchError as e:
        logger.warning('Encoder install failed: %s', e)

Prevention

When it happens

Trigger: Running model scan/install on a directory containing model_index.json or a transformer/ subfolder while the Qwen3Encoder config's from_model_on_disk probes it.

Common situations: Pointing InvokeAI at a full HuggingFace pipeline checkout (e.g. a FLUX.2 or Z-Image repo root) and expecting only the encoder to be imported; downloading a whole repo with git clone instead of only the text_encoder subfolder.

Related errors


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