invoke-ai/InvokeAI · error · ValueError

Unsupported controlnet type: {type(self.control)}

Error message

Unsupported controlnet type: {type(self.control)}

What it means

The control field of FLUX Denoise must be either None, a single FluxControlNetField, or a list of FluxControlNetFields. Any other object type on self.control cannot be interpreted as ControlNet input, so _prep_controlnet_extensions raises with the actual type.

Source

Thrown at invokeai/app/invocations/flux_denoise.py:728

    def _prep_controlnet_extensions(
        self,
        context: InvocationContext,
        exit_stack: ExitStack,
        latent_height: int,
        latent_width: int,
        dtype: torch.dtype,
        device: torch.device,
    ) -> list[XLabsControlNetExtension | InstantXControlNetExtension]:
        # Normalize the controlnet input to list[ControlField].
        controlnets: list[FluxControlNetField]
        if self.control is None:
            controlnets = []
        elif isinstance(self.control, FluxControlNetField):
            controlnets = [self.control]
        elif isinstance(self.control, list):
            controlnets = self.control
        else:
            raise ValueError(f"Unsupported controlnet type: {type(self.control)}")

        # TODO(ryand): Add a field to the model config so that we can distinguish between XLabs and InstantX ControlNets
        # before loading the models. Then make sure that all VAE encoding is done before loading the ControlNets to
        # minimize peak memory.

        # Calculate the controlnet conditioning tensors.
        # We do this before loading the ControlNet models because it may require running the VAE, and we are trying to
        # keep peak memory down.
        controlnet_conds: list[torch.Tensor] = []
        for controlnet in controlnets:
            image = context.images.get_pil(controlnet.image.image_name)

            # HACK(ryand): We have to load the ControlNet model to determine whether the VAE needs to be run. We really
            # shouldn't have to load the model here. There's a risk that the model will be dropped from the model cache
            # before we load it into VRAM and thus we'll have to load it again (context:
            # https://github.com/invoke-ai/InvokeAI/issues/7513).
            controlnet_model = context.models.load(controlnet.control_model)
            if isinstance(controlnet_model.model, InstantXControlNetFlux):

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Wrap the ControlNet model reference in a FluxControlNetField (output of a FLUX ControlNet loader node) and connect that.
  2. Pass None (or omit) instead of an empty/mismatched value when no ControlNet is needed.
  3. Pass a list of FluxControlNetField items for multiple ControlNets.

Example fix

// before
denoise.control = rawImageField; // wrong type
// after
denoise.control = new FluxControlNetField(controlModel, image, controlWeight);
Defensive patterns

Strategy: type-guard

Validate before calling

if denoise.control is not None and not isinstance(denoise.control, (FluxControlNetField, list)):
    raise ValueError('control must be FluxControlNetField or list of them')

Type guard

def is_valid_control(v) -> bool:
    if v is None:
        return True
    if isinstance(v, FluxControlNetField):
        return True
    return isinstance(v, list) and all(isinstance(x, FluxControlNetField) for x in v)

Try / catch

try:
    result = invoke(denoise)
except ValueError as e:
    if 'Unsupported controlnet type' in str(e):
        denoise.control = None  # drop invalid control input
        result = invoke(denoise)
    else:
        raise

Prevention

When it happens

Trigger: Assigning an arbitrary object, wrong field type, or an incompatible node output to the control field of the FLUX Denoise invocation; a list containing mixed types is accepted by the isinstance(self.control, list) branch but a non-field scalar/dict is not.

Common situations: Wiring a non-ControlNet image field directly into control; version changes where the field type was renamed; programmatic graph building assigning a raw dict instead of a FluxControlNetField.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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