{"record":{"id":"78c304d8fcfe3829","repo":"invoke-ai/InvokeAI","slug":"a-controlnet-vae-is-required-when-using-an-instant","errorCode":null,"errorMessage":"A ControlNet VAE is required when using an InstantX FLUX ControlNet.","messagePattern":"A ControlNet VAE is required when using an InstantX FLUX ControlNet\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/flux_denoise.py","lineNumber":748,"sourceCode":"        # 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):\n                if self.controlnet_vae is None:\n                    raise ValueError(\"A ControlNet VAE is required when using an InstantX FLUX ControlNet.\")\n                vae_info = context.models.load(self.controlnet_vae.vae)\n                controlnet_conds.append(\n                    InstantXControlNetExtension.prepare_controlnet_cond(\n                        controlnet_image=image,\n                        vae_info=vae_info,\n                        latent_height=latent_height,\n                        latent_width=latent_width,\n                        dtype=dtype,\n                        device=device,\n                        resize_mode=controlnet.resize_mode,\n                    )\n                )\n            elif isinstance(controlnet_model.model, XLabsControlNetFlux):\n                controlnet_conds.append(\n                    XLabsControlNetExtension.prepare_controlnet_cond(\n                        controlnet_image=image,\n                        latent_height=latent_height,\n                        latent_width=latent_width,","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/flux_denoise.py#L730-L766","documentation":"InstantX FLUX ControlNets apply their conditioning by encoding the control image through a VAE. The invocation requires that VAE to be supplied via the controlnet_vae field; when the loaded ControlNet is an InstantXControlNetFlux and controlnet_vae is None, it raises instead of proceeding without conditioning.","triggerScenarios":"Using a FLUX ControlNet model that resolves to InstantXControlNetFlux while leaving controlnet_vae unset on the FLUX Denoise invocation; the check occurs per-ControlNet in _prep_controlnet_extensions after loading the ControlNet model.","commonSituations":"Selecting an InstantX ControlNet (e.g. InstantX Canny/Depth for FLUX) in a workflow built for XLabs ControlNets, which don't need the VAE field; forgetting the VAE connection when switching ControlNet models.","solutions":["Connect a FLUX-compatible VAE to the controlnet_vae field of the FLUX Denoise invocation.","Switch to an XLabs FLUX ControlNet model if a VAE input is not desired (XLabs variants don't require it).","Verify the workflow's VAE loader feeds the denoise node before running the graph."],"exampleFix":"// before\ndenoise.control = instantXControlNetField; // controlnet_vae unset\n// after\ndenoise.control = instantXControlNetField;\ndenoise.controlnet_vae = vaeField; // required for InstantX ControlNets","handlingStrategy":"validation","validationCode":"if denoise.control is not None and denoise.controlnet_vae is None:\n    # InstantX FLUX ControlNets require a VAE\n    raise ValueError('controlnet_vae is required for InstantX FLUX ControlNets')","typeGuard":"def instantx_control_ready(denoise) -> bool:\n    return denoise.control is None or denoise.controlnet_vae is not None","tryCatchPattern":"try:\n    result = invoke(denoise)\nexcept ValueError as e:\n    if 'ControlNet VAE is required' in str(e):\n        denoise.controlnet_vae = load_flux_vae()\n        result = invoke(denoise)\n    else:\n        raise","preventionTips":["Always wire a VAE when using InstantX FLUX ControlNets","Prefer XLabs ControlNet models if you want to avoid the VAE dependency","Validate required edges (controlnet_vae) before running ControlNet workflows"],"tags":["controlnet","instantx","vae","missing-input"],"backgroundTag":"missing-required-input","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}