invoke-ai/InvokeAI · info · NotAMatchError

transformer is SDNQ-quantized; use Main_SDNQ_Diffusers_Flux2

Error message

transformer is SDNQ-quantized; use Main_SDNQ_Diffusers_Flux2_Config

What it means

The FLUX.2 diffusers config raises NotAMatchError when the pipeline's `transformer/` folder is SDNQ-quantized, so that Main_SDNQ_Diffusers_Flux2_Config claims the model instead. Without this guard both configs would accept the same folder and identification could latch onto the wrong one; the plain diffusers loader would then misread packed uint8 weights as bf16 and crash with size-mismatch errors at first inference.

Source

Thrown at invokeai/backend/model_manager/configs/main.py:1032

                "a loose transformer-only checkout cannot be used as a FLUX.2 main model"
            )

        # Check for FLUX.2-specific pipeline class names
        raise_for_class_name(
            common_config_paths(mod.path),
            {
                "Flux2KleinPipeline",
                "Flux2Pipeline",
                "Flux2Transformer2DModel",
            },
        )

        # Reject SDNQ-quantized pipelines so the SDNQ-specific config matches them instead.
        # Without this both configs accept the same folder and identification can latch onto
        # the wrong one (the plain diffusers loader would then mis-read packed uint8 weights
        # as bf16 and crash with size-mismatch errors at first inference).
        if (mod.path / "transformer").is_dir() and _is_sdnq_folder(mod.path / "transformer"):
            raise NotAMatchError("transformer is SDNQ-quantized; use Main_SDNQ_Diffusers_Flux2_Config")

        variant = override_fields.pop("variant", None) or cls._get_variant_or_raise(mod)

        repo_variant = override_fields.pop("repo_variant", None) or cls._get_repo_variant_or_raise(mod)

        return cls(
            **override_fields,
            variant=variant,
            repo_variant=repo_variant,
        )

    @classmethod
    def _get_variant_or_raise(cls, mod: ModelOnDisk) -> Flux2VariantType:
        """Determine the FLUX.2 variant from the transformer config.

        FLUX.2 variants are distinguished by joint_attention_dim (= 3 × text encoder hidden_size):
        - Klein 4B/4B Base: 7680 (3 × Qwen3-4B 2560)
        - Klein 9B/9B Base: 12288 (3 × Qwen3-8B 4096)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Nothing to fix: this steer makes the SDNQ-specific FLUX.2 config match instead.
  2. If registration ultimately fails, upgrade InvokeAI so Main_SDNQ_Diffusers_Flux2_Config is available.
  3. To use plain diffusers loading, obtain the non-quantized (bf16) FLUX.2 weights.
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def is_sdnq_flux2(folder: Path) -> bool:
    t = folder / "transformer"
    return t.is_dir() and ((t / "quantization_config.json").exists() or any(t.glob("*.sdnq")))

if is_sdnq_flux2(Path(model_dir)):
    expect_config = "Main_SDNQ_Diffusers_Flux2_Config"

Type guard

def is_sdnq_transformer(folder: Path) -> bool:
    return folder.is_dir() and (folder / "quantization_config.json").is_file()

Try / catch

try:
    cfg = Main_Diffusers_Flux2_Config.from_model_on_disk(mod)
except NotAMatchError:
    cfg = Main_SDNQ_Diffusers_Flux2_Config.from_model_on_disk(mod)

Prevention

When it happens

Trigger: Identifying a FLUX.2 pipeline folder where `mod.path/transformer` is a directory containing SDNQ quantization markers, via the model-manager scan/install path that calls from_model_on_disk.

Common situations: Auto-registration of an SDNQ-quantized FLUX.2 download; normally invisible to users except as correct SDNQ classification. Becomes a real problem only if the SDNQ FLUX.2 config is missing (older InvokeAI version) and the model then fails to register.

Related errors


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