{"record":{"id":"f4502e995f684576","repo":"invoke-ai/InvokeAI","slug":"unsupported-controlnet-type-type-self-control","errorCode":null,"errorMessage":"Unsupported controlnet type: {type(self.control)}","messagePattern":"Unsupported controlnet type: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/flux_denoise.py","lineNumber":728,"sourceCode":"    def _prep_controlnet_extensions(\n        self,\n        context: InvocationContext,\n        exit_stack: ExitStack,\n        latent_height: int,\n        latent_width: int,\n        dtype: torch.dtype,\n        device: torch.device,\n    ) -> list[XLabsControlNetExtension | InstantXControlNetExtension]:\n        # Normalize the controlnet input to list[ControlField].\n        controlnets: list[FluxControlNetField]\n        if self.control is None:\n            controlnets = []\n        elif isinstance(self.control, FluxControlNetField):\n            controlnets = [self.control]\n        elif isinstance(self.control, list):\n            controlnets = self.control\n        else:\n            raise ValueError(f\"Unsupported controlnet type: {type(self.control)}\")\n\n        # TODO(ryand): Add a field to the model config so that we can distinguish between XLabs and InstantX ControlNets\n        # before loading the models. Then make sure that all VAE encoding is done before loading the ControlNets to\n        # minimize peak memory.\n\n        # Calculate the controlnet conditioning tensors.\n        # We do this before loading the ControlNet models because it may require running the VAE, and we are trying to\n        # keep peak memory down.\n        controlnet_conds: list[torch.Tensor] = []\n        for controlnet in controlnets:\n            image = context.images.get_pil(controlnet.image.image_name)\n\n            # HACK(ryand): We have to load the ControlNet model to determine whether the VAE needs to be run. We really\n            # shouldn't have to load the model here. There's a risk that the model will be dropped from the model cache\n            # before we load it into VRAM and thus we'll have to load it again (context:\n            # https://github.com/invoke-ai/InvokeAI/issues/7513).\n            controlnet_model = context.models.load(controlnet.control_model)\n            if isinstance(controlnet_model.model, InstantXControlNetFlux):","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/flux_denoise.py#L710-L746","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wrap the ControlNet model reference in a FluxControlNetField (output of a FLUX ControlNet loader node) and connect that.","Pass None (or omit) instead of an empty/mismatched value when no ControlNet is needed.","Pass a list of FluxControlNetField items for multiple ControlNets."],"exampleFix":"// before\ndenoise.control = rawImageField; // wrong type\n// after\ndenoise.control = new FluxControlNetField(controlModel, image, controlWeight);","handlingStrategy":"type-guard","validationCode":"if denoise.control is not None and not isinstance(denoise.control, (FluxControlNetField, list)):\n    raise ValueError('control must be FluxControlNetField or list of them')","typeGuard":"def is_valid_control(v) -> bool:\n    if v is None:\n        return True\n    if isinstance(v, FluxControlNetField):\n        return True\n    return isinstance(v, list) and all(isinstance(x, FluxControlNetField) for x in v)","tryCatchPattern":"try:\n    result = invoke(denoise)\nexcept ValueError as e:\n    if 'Unsupported controlnet type' in str(e):\n        denoise.control = None  # drop invalid control input\n        result = invoke(denoise)\n    else:\n        raise","preventionTips":["Only connect FLUX ControlNet loader node outputs to the control field","Validate field types when building graphs programmatically","Use a list field for multiple ControlNets instead of ad-hoc structures"],"tags":["controlnet","type-error","flux","field-type"],"backgroundTag":"invalid-argument-type","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}