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
- Add `text_encoder_2/config.json` (or a root `config.json`) from the source repo
- Flatten the folder so the expected layout applies (remove the extra wrapper directory)
- 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
- Verify config.json exists after extracting archives
- Remove extra wrapper directories from downloaded zips
- Keep diffusers layout intact (config.json alongside weights)
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
- unrecognised/unsupported architecture for OMI LoRA: {archite
- model looks like Control LoRA
- model does not match LyCORIS LoRA heuristics
- model does not look like a Qwen Image Edit LoRA
- model does not match Krea-2 LoRA heuristics (no complete lor
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/4ea5f66b4a1f9991.
Report an issue: GitHub.