invoke-ai/InvokeAI · error · ValueError
InpaintModelExt should be used only on inpaint models!
Error message
InpaintModelExt should be used only on inpaint models!
What it means
InpaintModelExt feeds the 9-channel inpainting UNet, so init_tensors asserts _is_inpaint_model(ctx.unet) (conv_in.in_channels == 9). Attaching it to a normal 4-channel UNet raises ValueError — the inverse check of InpaintExt.
Source
Thrown at invokeai/backend/stable_diffusion/extensions/inpaint_model.py:61
if mask is not None:
self._mask = 1 - mask
self._masked_latents = masked_latents
self._is_gradient_mask = is_gradient_mask
@staticmethod
def _is_inpaint_model(unet: UNet2DConditionModel):
"""Checks if the provided UNet belongs to a regular model.
The `in_channels` of a UNet vary depending on model type:
- normal - 4
- depth - 5
- inpaint - 9
"""
return unet.conv_in.in_channels == 9
@callback(ExtensionCallbackType.PRE_DENOISE_LOOP)
def init_tensors(self, ctx: DenoiseContext):
if not self._is_inpaint_model(ctx.unet):
raise ValueError("InpaintModelExt should be used only on inpaint models!")
if self._mask is None:
self._mask = torch.ones_like(ctx.latents[:1, :1])
self._mask = self._mask.to(device=ctx.latents.device, dtype=ctx.latents.dtype)
if self._masked_latents is None:
self._masked_latents = torch.zeros_like(ctx.latents[:1])
self._masked_latents = self._masked_latents.to(device=ctx.latents.device, dtype=ctx.latents.dtype)
# Do last so that other extensions works with normal latents
@callback(ExtensionCallbackType.PRE_UNET, order=1000)
def append_inpaint_layers(self, ctx: DenoiseContext):
batch_size = ctx.unet_kwargs.sample.shape[0]
b_mask = torch.cat([self._mask] * batch_size)
b_masked_latents = torch.cat([self._masked_latents] * batch_size)
ctx.unet_kwargs.sample = torch.cat(
[ctx.unet_kwargs.sample, b_mask, b_masked_latents],
dim=1,View on GitHub (pinned to 0b6a024f2f)
Solutions
- Use InpaintExt (for normal models) instead of InpaintModelExt when the UNet is not 9-channel.
- Load an actual inpainting checkpoint (e.g. SD-inpainting variant) for this workflow.
- Re-probe/re-add the model if it was mislabeled in the model manager.
- Check unet.conv_in.in_channels == 9 before attaching the extension in custom code.
Example fix
// before
extensions.append(InpaintModelExt(mask, masked_latents)) # normal unet
// 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("InpaintModelExt requires an inpainting (9-channel) UNet") Type guard
def is_inpaint_model(unet) -> bool:
return unet.conv_in.in_channels == 9 Try / catch
try:
result = pipeline(...)
except ValueError as e:
if "InpaintModelExt should be used only on inpaint models" in str(e):
result = run_with_inpaint_ext(pipeline, mask, masked_latents)
else:
raise Prevention
- Only attach InpaintModelExt to 9-channel inpainting checkpoints
- Select the correct workflow for the loaded model type
- Verify model variant after re-adding/re-probing checkpoints
- Share one helper (conv_in.in_channels check) for extension selection
When it happens
Trigger: A denoise graph registers InpaintModelExt while the loaded UNet is a standard (non-inpainting) model, so the callback fires with the wrong unet.
Common situations: User selecting an inpaint-style workflow against a regular SD checkpoint; model misconfigured/mislabeled as inpainting; custom extension wiring that doesn't check unet type.
Related errors
- Source image required for inpaint mask when inpaint model us
- InpaintExt should be used only on normal (non-inpainting) mo
- Source image required for inpaint mask when inpaint model us
- Invalid mode selected
- Unexpected control_input type: ${type(control_input)}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/6f72cade7c7b3f0d.
Report an issue: GitHub.