invoke-ai/InvokeAI · error · ValueError

Unexpected submodel requested for PiD decoder.

Error message

Unexpected submodel requested for PiD decoder.

What it means

PiD decoders are self-contained models, not pipeline components: PiDDecoderLoader._load_model requires submodel_type to be None and raises ValueError if any submodel is requested. The backbone (Flux/SD3/SDXL/QwenImage) is taken from config.base, so there is nothing per-submodel to load.

Source

Thrown at invokeai/backend/model_manager/load/model_loaders/pid_decoder.py:57

@ModelLoaderRegistry.register(base=BaseModelType.Flux, type=ModelType.PiDDecoder, format=ModelFormat.Checkpoint)
@ModelLoaderRegistry.register(base=BaseModelType.Flux2, type=ModelType.PiDDecoder, format=ModelFormat.Checkpoint)
@ModelLoaderRegistry.register(
    base=BaseModelType.StableDiffusion3, type=ModelType.PiDDecoder, format=ModelFormat.Checkpoint
)
@ModelLoaderRegistry.register(
    base=BaseModelType.StableDiffusionXL, type=ModelType.PiDDecoder, format=ModelFormat.Checkpoint
)
@ModelLoaderRegistry.register(base=BaseModelType.QwenImage, type=ModelType.PiDDecoder, format=ModelFormat.Checkpoint)
class PiDDecoderLoader(ModelLoader):
    """Loads a PiD checkpoint into a fully-constructed PidNet of the matching backbone."""

    def _load_model(
        self,
        config: AnyModelConfig,
        submodel_type: Optional[SubModelType] = None,
    ) -> AnyModel:
        if submodel_type is not None:
            raise ValueError("Unexpected submodel requested for PiD decoder.")

        # Backbone is encoded in the config's `base` field — populated by
        # PiDDecoder_Checkpoint_*_Config when the user added the model.
        backbone: BaseModelType = config.base

        raw_sd = strip_net_prefix(_load_raw_checkpoint(Path(config.path)))

        # Build the live PidNet on CPU and pour the checkpoint in — then drop
        # the dict so we don't hold two copies in RAM at once.
        pid_net = load_pid_decoder(raw_sd, backbone)
        del raw_sd

        # We deliberately keep PidNet's parameters in float32 here. PiD
        # consumes Gemma-2 hidden states that contain large outliers
        # (per-token max well past 100) and the in-network RMSNorm
        # (`variance = hidden_states.pow(2).mean(-1, keepdim=True)`) loses
        # precision badly in bf16, producing all-NaN outputs. The decode
        # wrapper runs the forward pass under `torch.autocast(bf16)` so the

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Load PiD decoder models with submodel_type=None (omit the argument).
  2. Exclude ModelType.PiDDecoder from generic per-submodel loading loops.
  3. Read config.base if you need to know which backbone the decoder targets.
  4. Call the higher-level decode wrapper rather than treating the decoder as a pipeline submodel.

Example fix

// before
pid = loader._load_model(cfg, SubModelType.Vae)  # ValueError
// after
pid = loader._load_model(cfg)  # submodel_type must be None
Defensive patterns

Strategy: validation

Validate before calling

if submodel_type is not None:
    raise ValueError("PiD decoders are standalone: call with submodel_type=None")
pid = loader._load_model(cfg)  # backbone comes from cfg.base

Try / catch

try:
    pid = loader._load_model(cfg, submodel_type)
except ValueError as e:
    if "Unexpected submodel requested for PiD decoder" in str(e):
        pid = loader._load_model(cfg)
    else:
        raise

Prevention

When it happens

Trigger: Pipeline-assembly or generic loading code that requests a SubModelType (e.g. SubModelType.UNet or VAE) while loading a ModelType.PiDDecoder record, or direct _load_model calls that pass a non-None submodel.

Common situations: Code that iterates all submodel types for every model in a pipeline; treating the PiD decoder like a main model with subfolders; test scripts reusing main-model loading helpers.

Related errors


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