{"record":{"id":"72cd23966b28e787","repo":"Comfy-Org/ComfyUI","slug":"qwen-fun-controlnet-requires-a-control-hint-image","errorCode":null,"errorMessage":"Qwen Fun ControlNet requires a control hint image.","messagePattern":"Qwen Fun ControlNet requires a control hint image\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"comfy/ldm/qwen_image/controlnet.py","lineNumber":133,"sourceCode":"        attention_mask=None,\n        guidance: torch.Tensor = None,\n        hint=None,\n        transformer_options={},\n        base_model=None,\n        **kwargs,\n    ):\n        if base_model is None:\n            raise RuntimeError(\"Qwen Fun ControlNet requires a QwenImage base model at runtime.\")\n\n        encoder_hidden_states_mask = attention_mask\n        # Keep attention mask disabled inside Fun control blocks to mirror\n        # VideoX behavior (they rely on seq lengths for RoPE, not masked attention).\n        encoder_hidden_states_mask = None\n\n        hidden_states, img_ids, _ = base_model.process_img(x)\n        hint_tokens = self._process_hint_tokens(hint)\n        if hint_tokens is None:\n            raise RuntimeError(\"Qwen Fun ControlNet requires a control hint image.\")\n\n        if hint_tokens.shape[1] != hidden_states.shape[1]:\n            max_tokens = min(hint_tokens.shape[1], hidden_states.shape[1])\n            hint_tokens = hint_tokens[:, :max_tokens]\n            hidden_states = hidden_states[:, :max_tokens]\n            img_ids = img_ids[:, :max_tokens]\n\n        txt_start = round(\n            max(\n                ((x.shape[-1] + (base_model.patch_size // 2)) // base_model.patch_size) // 2,\n                ((x.shape[-2] + (base_model.patch_size // 2)) // base_model.patch_size) // 2,\n            )\n        )\n        txt_ids = torch.arange(txt_start, txt_start + context.shape[1], device=x.device).reshape(1, -1, 1).repeat(x.shape[0], 1, 3)\n        ids = torch.cat((txt_ids, img_ids), dim=1)\n        image_rotary_emb = base_model.pe_embedder(ids).to(x.dtype).contiguous()\n\n        hidden_states = base_model.img_in(hidden_states)","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/qwen_image/controlnet.py#L115-L151","documentation":"After resolving the base model, the Qwen Fun ControlNet must convert a control image ('hint') into hint tokens; _process_hint_tokens returns None when no usable hint was passed, and the code raises RuntimeError immediately. The hint is the structural conditioning (depth/pose/canny/etc.) and is mandatory for Fun controlnets.","triggerScenarios":"Applying Qwen Fun ControlNet through the proper apply node but leaving the control image input empty; passing hint=None via custom code; the control-image preprocessor node is bypassed so None flows into the apply node.","commonSituations":"Workflow copied from a text-only example where the image input was never wired; preprocessor (e.g. depth estimator) muted/bypassed; empty image mask or a load-image node pointing at a missing file yielding None.","solutions":["Connect a control image (or preprocessor output) to the control image input of the Fun ControlNet apply node.","Un-bypass/unmute any preprocessor nodes feeding the hint.","Verify the image tensor is non-empty and has the expected CHW/BHWC layout the apply node expects.","If you did not intend image control, remove the Fun ControlNet from the conditioning chain entirely."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"def validate_hint(hint):\n    import torch\n    if hint is None or (torch.is_tensor(hint) and hint.numel() == 0):\n        raise ValueError(\"Fun ControlNet needs a non-empty control image; check preprocessor wiring\")\n    return hint","typeGuard":"def has_control_image(hint) -> bool:\n    import torch\n    return torch.is_tensor(hint) and hint.numel() > 0 and hint.dim() >= 3","tryCatchPattern":null,"preventionTips":["Connect a preprocessor or load-image node to the control image input before applying the controlnet.","Bypassed preprocessors pass None — unmute them.","Smoke-test workflows with a tiny dummy control image before long runs."],"tags":["qwen-image","controlnet","control-image","validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}