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

Flux.forward expects the image latent tensor (img) and text embedding tensor (txt) to be rank-3: (batch, seq_len, channels). If either has another rank (e.g. 4D image latents straight from the VAE, or 2D unbatched tensors), the sequence-linear projections downstream would be wrong, so forward raises immediately.

Source

Thrown at invokeai/backend/flux/model.py:107

    def forward(
        self,
        img: Tensor,
        img_ids: Tensor,
        txt: Tensor,
        txt_ids: Tensor,
        timesteps: Tensor,
        y: Tensor,
        guidance: Tensor | None,
        timestep_index: int,
        total_num_timesteps: int,
        controlnet_double_block_residuals: list[Tensor] | None,
        controlnet_single_block_residuals: list[Tensor] | None,
        ip_adapter_extensions: list[XLabsIPAdapterExtension],
        regional_prompting_extension: RegionalPromptingExtension,
    ) -> Tensor:
        if img.ndim != 3 or txt.ndim != 3:
            raise ValueError("Input img and txt tensors must have 3 dimensions.")

        # running on sequences img
        img = self.img_in(img)
        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)

        ids = torch.cat((txt_ids, img_ids), dim=1)
        pe = self.pe_embedder(ids)

        # Validate double_block_residuals shape.
        if controlnet_double_block_residuals is not None:
            assert len(controlnet_double_block_residuals) == len(self.double_blocks)
        for block_index, block in enumerate(self.double_blocks):

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Reshape img to (batch, seq_len, channels) — for Flux, pack latents first (2x2 patchify then rearrange to B, seq, C)
  2. Reshape txt to (batch, seq_len, embed_dim) from your text encoder output
  3. Add .unsqueeze(0) if you forgot the batch dimension

Example fix

// before
img = vae.encode(image)  # B,C,H,W
model(img=img, txt=t5_embeddings, ...)
// after
img = pack_latents(vae.encode(image))  # B, seq, 64
model(img=img, txt=t5_embeddings, ...)  # txt: B, seq, 4096
Defensive patterns

Strategy: validation

Validate before calling

assert img.ndim == 3 and txt.ndim == 3, f"img: {img.shape}, txt: {txt.shape} — both must be (batch, seq, channels)"

Type guard

def is_rank3_tensor(t: torch.Tensor) -> bool:
    return isinstance(t, torch.Tensor) and t.ndim == 3

Try / catch

try:
    output = model(img=img, txt=txt, ...)
except ValueError as e:
    if "must have 3 dimensions" in str(e):
        img = img.flatten(2).transpose(1, 2) if img.ndim == 4 else img.unsqueeze(0)
        txt = txt.unsqueeze(0) if txt.ndim == 2 else txt
        output = model(img=img, txt=txt, ...)
    else:
        raise

Prevention

When it happens

Trigger: Calling model.forward (or __call__) with img or txt shaped (B,C,H,W) instead of (B,seq,C); passing a text encoder output without flattening token dims; passing an unbatched (seq,C) tensor.

Common situations: Wiring a diffusers-style UNet pipeline to Flux directly; forgetting pack/unpack of latents (Flux works on packed 2x2 patch latents of shape B, seq, 64); custom pipelines passing VAE latents untransformed.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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