invoke-ai/InvokeAI · error · ValueError
Input img and txt tensors must have 3 dimensions.
Error message
Input img and txt tensors must have 3 dimensions.
What it means
InstantXControlNetFlux.forward operates on sequence-form latent/text tokens, so both img (latent image tokens) and txt (T5 text tokens) must be rank-3 tensors of shape (batch, seq_len, channels). If either is rank-2 (e.g. (B, C) or a flat token row) or rank-4 (unflattened image feature map), the transformer math and attention ID concatenation would be wrong, so it raises immediately.
Source
Thrown at invokeai/backend/flux/controlnet/instantx_controlnet_flux.py:120
self.is_union = True
self.controlnet_mode_embedder = nn.Embedding(num_control_modes, self.hidden_size)
self.controlnet_x_embedder = zero_module(torch.nn.Linear(self.in_channels, self.hidden_size))
def forward(
self,
controlnet_cond: torch.Tensor,
controlnet_mode: torch.Tensor | None,
img: torch.Tensor,
img_ids: torch.Tensor,
txt: torch.Tensor,
txt_ids: torch.Tensor,
timesteps: torch.Tensor,
y: torch.Tensor,
guidance: torch.Tensor | None = None,
) -> InstantXControlNetFluxOutput:
if img.ndim != 3 or txt.ndim != 3:
raise ValueError("Input img and txt tensors must have 3 dimensions.")
img = self.img_in(img)
# Add controlnet_cond embedding.
img = img + self.controlnet_x_embedder(controlnet_cond)
vec = self.time_in(timestep_embedding(timesteps, 256))
if self.params.guidance_embed:
if guidance is None:
raise ValueError("Didn't get guidance strength for guidance distilled model.")
vec = vec + self.guidance_in(timestep_embedding(guidance, 256))
vec = vec + self.vector_in(y)
txt = self.txt_in(txt)
# If this is a union ControlNet, then concat the control mode embedding to the T5 text embedding.
if self.is_union:
if controlnet_mode is None:
# We allow users to enter 'None' as the controlnet_mode if they don't want to worry about this input.View on GitHub (pinned to 0b6a024f2f)
Solutions
- Ensure img has shape (batch, seq_len, hidden) — pack latents e.g. via rearrange/flatten of the patchified grid before calling forward.
- Ensure txt has shape (batch, t5_seq_len, 4096); do not squeeze the sequence dim even for batch size 1.
- Call img.ndim / txt.ndim (or assert both == 3) at the call site to catch shape bugs early.
- Use the pipeline's existing packing utilities instead of hand-reshaping latents.
Example fix
// before img = latents # (B, 16, H, W) out = controlnet(img=img, txt=text_emb.squeeze(0), ...) // after img = rearrange(latents, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=2, pw=2) # (B, seq, dim) out = controlnet(img=img, txt=text_emb, ...) # keep (B, seq, 4096)
Defensive patterns
Strategy: validation
Validate before calling
assert img.ndim == 3, f"img must be (B, seq, dim), got shape {tuple(img.shape)}"
assert txt.ndim == 3, f"txt must be (B, seq, 4096), got shape {tuple(txt.shape)}" Type guard
def is_seq_tokens(t: torch.Tensor) -> bool:
return t.ndim == 3 Try / catch
try:
out = controlnet(img=img, txt=txt, ...)
except ValueError as e:
if "must have 3 dimensions" in str(e):
raise RuntimeError(f"bad shapes: img={tuple(img.shape)}, txt={tuple(txt.shape)}; pack latents to (B,seq,dim) first") from e
raise Prevention
- Always patchify latents (2x2 rearrange) before passing to Flux ControlNet.
- Never .squeeze() text embeddings on the sequence dimension.
- Check tensor .shape at the call boundary; log it when debugging pipelines.
When it happens
Trigger: Calling forward() with img or txt lacking a sequence dimension — e.g. passing a (B,C,H,W) latent tensor without packing it to (B, H*W, C), or passing a 2D (B,C) text embedding instead of (B, seq, 4096).
Common situations: Feeding raw VAE latents straight from the decoder without patchify/rearrange; squeezing text embeddings to 2D; batch-dim removal with batch size 1 (producing 2D tensors); reusing tensors shaped for diffusers' UNet-style APIs.
Related errors
- Got {params.axes_dim} but expected positional dim {pe_dim}
- Input img and txt tensors must have 3 dimensions.
- The Anima ControlNet-LLLite model '{lllite_field.control_mod
- This Anima ControlNet-LLLite adapter is an inpainting adapte
- Unsupported Anima ControlNet-LLLite adapter: expected 3 or 4
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/3586d8f188616eed.
Report an issue: GitHub.