invoke-ai/InvokeAI · error · ValueError

InpaintExt should be used only on normal (non-inpainting) mo

Error message

InpaintExt should be used only on normal (non-inpainting) models. This could be caused by an inpainting model that was incorrectly marked as a non-inpainting model. In some cases, this can be fixed by removing and re-adding the model (so that it gets re-probed).

What it means

InpaintExt is the extension for adding mask/source latents to NORMAL (4-channel) UNets by lerping them into the latents. init_tensors asserts the loaded UNet is not an inpainting model (9-channel); if it is, the wrong extension was attached and ValueError is raised. The message also flags likely model-probe misclassification.

Source

Thrown at invokeai/backend/stable_diffusion/extensions/inpaint.py:78

            t = einops.repeat(t, "-> batch", batch=batch_size)
        # Noise shouldn't be re-randomized between steps here. The multistep schedulers
        # get very confused about what is happening from step to step when we do that.
        mask_latents = ctx.scheduler.add_noise(ctx.inputs.orig_latents, self._noise, t)
        # TODO: Do we need to also apply scheduler.scale_model_input? Or is add_noise appropriately scaled already?
        # mask_latents = self.scheduler.scale_model_input(mask_latents, t)
        mask_latents = einops.repeat(mask_latents, "b c h w -> (repeat b) c h w", repeat=batch_size)
        if self._is_gradient_mask:
            threshold = (t.item()) / ctx.scheduler.config.num_train_timesteps
            mask_bool = mask < 1 - threshold
            masked_input = torch.where(mask_bool, latents, mask_latents)
        else:
            masked_input = torch.lerp(latents, mask_latents.to(dtype=latents.dtype), mask.to(dtype=latents.dtype))
        return masked_input

    @callback(ExtensionCallbackType.PRE_DENOISE_LOOP)
    def init_tensors(self, ctx: DenoiseContext):
        if not self._is_normal_model(ctx.unet):
            raise ValueError(
                "InpaintExt should be used only on normal (non-inpainting) models. This could be caused by an "
                "inpainting model that was incorrectly marked as a non-inpainting model. In some cases, this can be "
                "fixed by removing and re-adding the model (so that it gets re-probed)."
            )

        self._mask = self._mask.to(device=ctx.latents.device, dtype=ctx.latents.dtype)

        self._noise = ctx.inputs.noise
        # 'noise' might be None if the latents have already been noised (e.g. when running the SDXL refiner).
        # We still need noise for inpainting, so we generate it from the seed here.
        if self._noise is None:
            self._noise = torch.randn(
                ctx.latents.shape,
                dtype=torch.float32,
                device="cpu",
                generator=torch.Generator(device="cpu").manual_seed(ctx.seed),
            ).to(device=ctx.latents.device, dtype=ctx.latents.dtype)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Remove and re-add the model in the model manager so it is re-probed with the correct variant.
  2. Verify the checkpoint really is a non-inpainting model and choose the matching inpaint pipeline/extension instead (InpaintModelExt).
  3. Update InvokeAI in case the variant-probing bug is fixed upstream.
  4. Check is_inpainting_model(unet) (conv_in.in_channels == 9) before attaching InpaintExt in custom code.

Example fix

// before
extensions.append(InpaintExt(mask, masked_latents))  # unet is inpainting model
// after
if unet.conv_in.in_channels == 9:
    extensions.append(InpaintModelExt(mask, masked_latents))
else:
    extensions.append(InpaintExt(mask, masked_latents))
Defensive patterns

Strategy: validation

Validate before calling

if unet.conv_in.in_channels == 9:
    raise ValueError("InpaintExt cannot be used with an inpainting (9-channel) UNet")

Type guard

def is_normal_model(unet) -> bool:
    return unet.conv_in.in_channels != 9

Try / catch

try:
    result = pipeline(...)
except ValueError as e:
    if "InpaintExt should be used only on normal" in str(e):
        result = run_with_inpaint_model_ext(pipeline, mask, masked_latents)
    else:
        raise

Prevention

When it happens

Trigger: A denoise graph attaches InpaintExt while ctx.unet is an inpainting model, usually because the model was incorrectly probed/registered as a non-inpainting checkpoint.

Common situations: Model manager misdetecting an inpainting checkpoint's variant; user selecting the wrong pipeline type in the UI; stale model records after files were replaced with different variants.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/92b4041770643824. Report an issue: GitHub.