invoke-ai/InvokeAI · error · ValueError

Qwen3 encoder variant mismatch: FLUX.2 Klein {main_config.va

Error message

Qwen3 encoder variant mismatch: FLUX.2 Klein {main_config.variant.value} requires a {required_qwen3.value} encoder, but the {model_name} pipeline '{config.name}' ({source_variant.value}) carries {source_qwen3.value}. Select a Klein pipeline from the same family - 4B pairs with 4B, 9B with 9B.

What it means

_validate_encoder_source raised ValueError because the Qwen3 encoder carried by the source pipeline does not match the size required by the main Klein model's variant (e.g. a 9B encoder on a 4B Klein transformer). The loader enforces same-family pairing: Klein 4B pairs with Qwen3 4B, Klein 9B with Qwen3 8B.

Source

Thrown at invokeai/app/invocations/flux2_klein_model_loader.py:250

        """
        config = self._validate_diffusers_format(context, model, model_name)
        source_variant = getattr(config, "variant", None)
        source_qwen3 = _KLEIN_TO_QWEN3_VARIANT.get(source_variant)

        # An allowlist, not "reject [dev]": a future third FLUX.2 variant has to fail closed here
        # the way the [dev] loader's guard already makes it, rather than being silently accepted.
        if source_qwen3 is None:
            described = f"variant '{source_variant.value}'" if source_variant is not None else "not a Klein pipeline"
            raise ValueError(
                f"The {model_name} model must be a FLUX.2 Klein pipeline, "
                f"but the selected model '{config.name}' is {described}. "
                "Its text encoder is incompatible with the Klein transformer. "
                "(Its VAE is compatible - this only blocks encoder extraction.)"
            )

        required_qwen3 = _KLEIN_TO_QWEN3_VARIANT.get(getattr(main_config, "variant", None))
        if required_qwen3 is not None and source_qwen3 != required_qwen3:
            raise ValueError(
                f"Qwen3 encoder variant mismatch: FLUX.2 Klein {main_config.variant.value} requires a "
                f"{required_qwen3.value} encoder, but the {model_name} pipeline '{config.name}' "
                f"({source_variant.value}) carries {source_qwen3.value}. "
                "Select a Klein pipeline from the same family - 4B pairs with 4B, 9B with 9B."
            )

    def _validate_qwen3_encoder_variant(self, context: InvocationContext, main_config: AnyModelConfig) -> None:
        """Validate that the standalone Qwen3 encoder variant matches the FLUX.2 Klein variant.

        - FLUX.2 Klein 4B (and 4B Base) require the Qwen3 4B encoder
        - FLUX.2 Klein 9B (and 9B Base) require the Qwen3 8B encoder
        """
        if self.qwen3_encoder_model is None:
            return

        # `getattr(..., None)` rather than `hasattr`: the field can exist and still be None, and
        # comparing None against the expected variant would then raise `AttributeError` on
        # `.value` in the error path instead of the intended `ValueError`.

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Select a source Klein pipeline from the same family as the main model (4B pipeline for 4B model, 9B for 9B)
  2. Correct variant metadata on either model if the sizes actually match but tags differ
  3. Instead supply a standalone matching Qwen3 encoder via 'Qwen3 Encoder'
  4. Catch ValueError, read required vs source variants from both configs, and warn/redirect before invoke()

Example fix

// before
main = klein_4b_model; loader.qwen3_source_model = klein_9b_pipeline  # mismatch
// after
main_cfg = context.models.get_config(main)
src_cfg = context.models.get_config(source_pipeline)
assert _KLEIN_TO_QWEN3_VARIANT[main_cfg.variant] == _KLEIN_TO_QWEN3_VARIANT[src_cfg.variant]
loader.qwen3_source_model = klein_4b_pipeline
Defensive patterns

Strategy: validation

Validate before calling

main_cfg = context.models.get_config(main_model)
src_cfg = context.models.get_config(source_pipeline)
req = _KLEIN_TO_QWEN3_VARIANT.get(getattr(main_cfg, 'variant', None))
src = _KLEIN_TO_QWEN3_VARIANT.get(getattr(src_cfg, 'variant', None))
if req is not None and src != req:
    raise ValueError(f"encoder family mismatch: need {req}, source carries {src}")

Type guard

def encoder_family_matches(main_cfg, source_cfg) -> bool:
    return _KLEIN_TO_QWEN3_VARIANT.get(getattr(main_cfg, 'variant', None)) \
        == _KLEIN_TO_QWEN3_VARIANT.get(getattr(source_cfg, 'variant', None))

Try / catch

try:
    output = loader.invoke(context)
except ValueError as e:
    if 'Qwen3 encoder variant mismatch' in str(e) and 'carries' in str(e):
        loader.qwen3_source_model = select_same_family_pipeline(loader.model, context)
        output = loader.invoke(context)
    else:
        raise

Prevention

When it happens

Trigger: invoke() -> _validate_encoder_source where required_qwen3 = _KLEIN_TO_QWEN3_VARIANT[main_config.variant] exists but source_qwen3 (from the source pipeline's variant) differs from it.

Common situations: Mixing Klein 4B main model with a Klein 9B pipeline as encoder source (or vice versa); the model manager's variant tags mislabeled after manual import; grabbing whichever Klein pipeline is downloaded first.

Related errors


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