{"record":{"id":"f1cc2f656e8ad6d7","repo":"invoke-ai/InvokeAI","slug":"source-image-required-for-inpaint-mask-when-inpain","errorCode":null,"errorMessage":"Source image required for inpaint mask when inpaint model used!","messagePattern":"Source image required for inpaint mask when inpaint model used!","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/backend/stable_diffusion/diffusers_pipeline.py","lineNumber":530,"sourceCode":"                required_padding_height = math.ceil(latents.size()[-2] / scale_factor) - tensor.size()[-2]\n                tensor = torch.nn.functional.pad(\n                    tensor,\n                    (0, required_padding_width, 0, required_padding_height, 0, 0, 0, 0),\n                    mode=\"constant\",\n                    value=0,\n                )\n                accum_adapter_state[idx] = tensor\n\n            down_intrablock_additional_residuals = accum_adapter_state\n\n        # Handle inpainting models.\n        if is_inpainting_model(self.unet):\n            # NOTE: These calls to add_inpainting_channels_to_latents(...) are intentionally done *after*\n            # self.scheduler.scale_model_input(...) so that the scaling is not applied to the mask or reference image\n            # latents.\n            if mask is not None:\n                if masked_latents is None:\n                    raise ValueError(\"Source image required for inpaint mask when inpaint model used!\")\n                latent_model_input = self.add_inpainting_channels_to_latents(\n                    latents=latent_model_input, masked_ref_image_latents=masked_latents, inpainting_mask=mask\n                )\n            else:\n                # We are using an inpainting model, but no mask was provided, so we are not really \"inpainting\".\n                # We generate a global mask and empty original image so that we can still generate in this\n                # configuration.\n                # TODO(ryand): Should we just raise an exception here instead? I can't think of a use case for wanting\n                # to do this.\n                # TODO(ryand): If we decide that there is a good reason to keep this, then we should generate the 'fake'\n                # mask and original image once rather than on every denoising step.\n                latent_model_input = self.add_inpainting_channels_to_latents(\n                    latents=latent_model_input,\n                    masked_ref_image_latents=torch.zeros_like(latent_model_input[:1]),\n                    inpainting_mask=torch.ones_like(latent_model_input[:1, :1]),\n                )\n\n        uc_noise_pred, c_noise_pred = self.invokeai_diffuser.do_unet_step(","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/backend/stable_diffusion/diffusers_pipeline.py#L512-L548","documentation":"When the UNet is an inpainting model (9 input channels), the pipeline must concatenate mask and masked-reference-image latents at each denoising step. If a mask is supplied but masked_latents (the source-image latents) is None, the required channels cannot be built and ValueError is raised in step().","triggerScenarios":"Calling pipeline.step(...) (or higher-level generation) with is_inpainting_model(unet)==True, passing a mask tensor but no masked_latents.","commonSituations":"Img2img/inpaint jobs where the user supplied a mask but the source image failed to encode or was dropped; API misuse calling low-level step() directly; regional/inpaint extension misconfiguration leaving masked_latents unset.","solutions":["Always provide masked_latents (latents of the masked source image) when passing a mask to an inpainting model.","If no real source image exists, pass an empty/black image as the source so masked_latents can be computed.","If you don't intend inpainting, omit the mask so the pipeline can synthesize a global mask and empty original image instead.","Verify upstream pipeline args (mask vs masked_latents) are populated together by the caller."],"exampleFix":"// before\npipeline.step(..., mask=mask, masked_latents=None)\n// after\nmasked_latents = vae.encode(source_image * (1 - mask))\npipeline.step(..., mask=mask, masked_latents=masked_latents)","handlingStrategy":"validation","validationCode":"if is_inpainting_model(pipeline.unet) and mask is not None:\n    assert masked_latents is not None, \"masked_latents required with mask for inpaint models\"","typeGuard":"def has_complete_inpaint_args(mask, masked_latents) -> bool:\n    return mask is None or masked_latents is not None","tryCatchPattern":"try:\n    result = pipeline.latents_from_embeddings(...)\nexcept ValueError as e:\n    if \"Source image required\" in str(e):\n        raise UserInputError(\"Provide a source image together with the inpaint mask\") from e\n    raise","preventionTips":["Always encode the source image when a mask is present","Validate mask+masked_latents pairing before calling step()","Provide an empty source image for mask-only flows","Check is_inpainting_model(unet) to know which args are mandatory"],"tags":["python","valueerror","inpainting","missing-argument"],"backgroundTag":"missing-inpaint-source-image","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}