{"record":{"id":"1814a45c86cd9fd7","repo":"invoke-ai/InvokeAI","slug":"negative-conditioning-is-required-when-cfg-scale","errorCode":null,"errorMessage":"Negative conditioning is required when cfg_scale != 1.0","messagePattern":"Negative conditioning is required when cfg_scale != 1\\.0","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/ernie_image/denoise.py","lineNumber":122,"sourceCode":"            img = _blend_init_latents(init_latents, img, float(scheduler.sigmas[0]))\n\n        # Higher-order solvers evaluate the model more than once per requested step (Heun's\n        # `set_timesteps(N)` yields 2N-1 timesteps), so drive progress off the actual iteration\n        # count rather than the requested step count.\n        total_steps = len(scheduler.timesteps)\n\n        pbar = tqdm(total=total_steps, desc=\"ERNIE-Image denoising\")\n        for step_index in range(total_steps):\n            timestep = scheduler.timesteps[step_index]\n            # The scheduler's timestep is already in `[0, num_train_timesteps]`; pass directly.\n            t_model = timestep.item()\n            t_vec = torch.full((img.shape[0],), t_model, dtype=img.dtype, device=img.device)\n\n            pred = _forward(model, img, t_vec, text_bth, text_lens)\n            step_cfg = cfg_scale[min(step_index, len(cfg_scale) - 1)]\n            if not math.isclose(step_cfg, 1.0):\n                if neg_text_bth is None or neg_text_lens is None:\n                    raise ValueError(\"Negative conditioning is required when cfg_scale != 1.0\")\n                neg_pred = _forward(model, img, t_vec, neg_text_bth, neg_text_lens)\n                pred = neg_pred + step_cfg * (pred - neg_pred)\n\n            # `generator` matters for stochastic schedulers (LCM re-noises every step). Euler and\n            # Heun accept it too and only consult it when `s_churn > 0`, which is 0 on this path.\n            img = scheduler.step(model_output=pred, timestep=timestep, sample=img, generator=generator).prev_sample\n\n            t_prev = scheduler.sigmas[step_index + 1].item() if step_index + 1 < len(scheduler.sigmas) else 0.0\n            if inpaint_extension is not None:\n                img = inpaint_extension.merge_intermediate_latents_with_init_latents(img, t_prev)\n\n            pbar.update(1)\n            # Predicted x0 estimate, unpatched so the preview decoder can use standard\n            # 32-channel latent RGB factors. `img` has already been stepped to `t_prev`, so the\n            # x0 estimate must use `t_prev` (using the pre-step sigma would over-subtract).\n            preview = unpatchify_latents(img - t_prev * pred)\n            step_callback(\n                PipelineIntermediateState(","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/ernie_image/denoise.py#L104-L140","documentation":"In the Heun denoise path, classifier-free guidance needs both conditional and negative (unconditional) predictions whenever cfg_scale != 1.0 for a given step. If negative text embeddings (neg_text_bth/neg_text_lens) were not supplied, the library raises ValueError because it cannot compute the guided prediction.","triggerScenarios":"Calling denoise() with a cfg_scale (any per-step entry) != 1.0 while passing neg_text_bth=None or neg_text_lens=None through the Heun branch.","commonSituations":"Graphs omitting the negative prompt node while setting CFG > 1; pipelines migrated from CFG-free workflows where cfg_scale was previously 1.0.","solutions":["Provide negative conditioning tensors (encode the negative prompt and pass neg_text_bth/neg_text_lens).","Set cfg_scale to 1.0 if you don't want classifier-free guidance and have no negative prompt.","Encode an empty-string negative prompt as a default in your graph."],"exampleFix":"// before\ndenoise(model, cfg_scale=3.0, neg_text_bth=None)\n// after\nneg_bth, neg_lens = encode_text(model, \"\")\ndenoise(model, cfg_scale=3.0, neg_text_bth=neg_bth, neg_text_lens=neg_lens)","handlingStrategy":"validation","validationCode":"if any(c != 1.0 for c in cfg_scale) and (neg_text_bth is None or neg_text_lens is None):\n    raise ValueError(\"encode a negative prompt before enabling CFG\")","typeGuard":"def has_negative_conditioning(neg_bth, neg_lens) -> bool:\n    return neg_bth is not None and neg_lens is not None","tryCatchPattern":"try:\n    img = denoise(model, cfg_scale=cfg, neg_text_bth=neg_bth, neg_text_lens=neg_lens)\nexcept ValueError as e:\n    if \"Negative conditioning\" in str(e):\n        neg_bth, neg_lens = encode_text(model, \"\")\n        img = denoise(model, cfg_scale=cfg, neg_text_bth=neg_bth, neg_text_lens=neg_lens)\n    else:\n        raise","preventionTips":["Always wire a negative prompt node (empty string is fine) when cfg_scale != 1.0.","Set cfg_scale=1.0 for guidance-free/distilled workflows.","Encode negative conditioning once and cache it per run."],"tags":["diffusion","cfg","validation"],"backgroundTag":"missing-negative-conditioning","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}