invoke-ai/InvokeAI · info · NotAMatchError

no text_encoder_2/config.json or config.json at model root

Error message

no text_encoder_2/config.json or config.json at model root

What it means

NotAMatchError from _locate_text_encoder_dir (called by T5Encoder_SDNQ_Config.from_model_on_disk). The helper resolve_text_encoder_dir looks for `text_encoder_2/config.json` or a root `config.json`; if neither exists the code cannot locate the T5 encoder directory and declines the match.

Source

Thrown at invokeai/backend/model_manager/configs/t5_encoder.py:175

        """Return the ``tokenizer_2/`` directory for either layout, or None if it doesn't exist.

        In the standalone-bundle layout ``tokenizer_2/`` is a child of the pipeline root; in the
        inline layout (``path`` is the ``text_encoder_2`` folder) it's a *sibling* of that folder.
        The encoder loader picks the encoder dir by the same layout test, so the tokenizer must too —
        using ``path / "tokenizer_2"`` unconditionally is wrong for the inline case.
        """
        if (path / "text_encoder_2" / "config.json").exists():
            candidate = path / "tokenizer_2"
        else:
            candidate = path.parent / "tokenizer_2"
        return candidate if candidate.exists() else None

    @classmethod
    def _locate_text_encoder_dir(cls, mod: ModelOnDisk):
        """Return the directory that actually holds T5's config.json + safetensors."""
        te_dir = cls.resolve_text_encoder_dir(mod.path)
        if te_dir is None:
            raise NotAMatchError("no text_encoder_2/config.json or config.json at model root")
        return te_dir

    @classmethod
    def _raise_if_not_sdnq_quantized(cls, te_dir) -> None:
        quant_config_path = te_dir / "quantization_config.json"
        if quant_config_path.exists():
            try:
                with open(quant_config_path, "r", encoding="utf-8") as f:
                    quant_config = json.load(f)
            except (OSError, ValueError):
                quant_config = {}
            if quant_config.get("quant_method") == "sdnq":
                return

        if _safetensors_dir_has_sdnq_keys(te_dir):
            return

        raise NotAMatchError("text_encoder_2 does not look like an SDNQ-quantized T5 encoder")

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Add `text_encoder_2/config.json` (or a root `config.json`) from the source repo
  2. Flatten the folder so the expected layout applies (remove the extra wrapper directory)
  3. Re-download the model ensuring config.json is included

Example fix

// before
downloads/model-wrapper/mymodel/text_encoder_2/config.json  (model root = downloads/model-wrapper)
// after
mymodel/text_encoder_2/config.json  (model root = mymodel)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
def has_encoder_config(model_dir: Path) -> bool:
    return (model_dir / "config.json").exists() or (model_dir / "text_encoder_2" / "config.json").exists()

Try / catch

try:
    install_model(path)
except NotAMatchError as e:
    if "config.json" in str(e):
        logger.error("Missing T5 config.json; re-download or flatten the folder layout")

Prevention

When it happens

Trigger: from_model_on_disk on a model dir with no `text_encoder_2/config.json` and no `config.json` at the root — weights present but config missing, or everything nested one level too deep.

Common situations: Partial downloads that skip config.json, archives that extract into an extra wrapper directory, or manually assembled folders missing diffusers config files.

Related errors


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