huggingface/candle · error

unexpected shape for img {:?}

Error message

unexpected shape for img {:?}

What it means

Same rank check as for txt but for img: FluxModel forward requires img (image token embeddings / latents) to be rank-3 [batch, img_seq, hidden]. A rank != 3 image tensor cannot be position-embedded and attention-processed, so forward bails.

Source

Thrown at candle-transformers/src/models/flux/quantized_model.rs:435

}

impl super::WithForward for Flux {
    #[allow(clippy::too_many_arguments)]
    fn forward(
        &self,
        img: &Tensor,
        img_ids: &Tensor,
        txt: &Tensor,
        txt_ids: &Tensor,
        timesteps: &Tensor,
        y: &Tensor,
        guidance: Option<&Tensor>,
    ) -> Result<Tensor> {
        if txt.rank() != 3 {
            candle::bail!("unexpected shape for txt {:?}", txt.shape())
        }
        if img.rank() != 3 {
            candle::bail!("unexpected shape for img {:?}", img.shape())
        }
        let dtype = img.dtype();
        let pe = {
            let ids = Tensor::cat(&[txt_ids, img_ids], 1)?;
            ids.apply(&self.pe_embedder)?
        };
        let mut txt = txt.apply(&self.txt_in)?;
        let mut img = img.apply(&self.img_in)?;
        let vec_ = timestep_embedding(timesteps, 256, dtype)?.apply(&self.time_in)?;
        let vec_ = match (self.guidance_in.as_ref(), guidance) {
            (Some(g_in), Some(guidance)) => {
                (vec_ + timestep_embedding(guidance, 256, dtype)?.apply(g_in))?
            }
            _ => vec_,
        };
        let vec_ = (vec_ + y.apply(&self.vector_in))?;

        // Double blocks

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Reshape latents to [batch, img_seq, hidden] — pack 2x2 patches via rearrange before calling forward
  2. Unsqueeze(0) if the batch dim is missing
  3. Confirm img.dims().len() == 3 prior to the call

Example fix

// before
let img = img; // [b, 16, h, w]
model.forward(&txt, &img, ...)?;
// after
let (b, _c, h, w) = img.dims4()?;
let img = img.reshape((b, 16, h / 2, 2, w / 2, 2))?
    .permute((0, 2, 4, 1, 3, 5))?
    .reshape((b, (h / 2) * (w / 2), 16 * 4))?;
model.forward(&txt, &img, ...)?;
Defensive patterns

Strategy: validation

Validate before calling

assert_eq!(img.dims().len(), 3, "img must be [batch, img_seq, hidden], got {:?}", img.shape());

Type guard

fn is_rank3(t: &candle_core::Tensor) -> bool { t.rank() == 3 }

Try / catch

match model.forward(&txt, &img, /* ... */) {
    Err(e) if e.to_string().contains("unexpected shape for img") =>
        Err(anyhow!("pack latents to token sequence [b, seq, d] before forward: {e}")),
    r => r.map_err(Into::into),
}

Prevention

When it happens

Trigger: Passing latents as [b, c, h, w] (4D conv-style) without flattening to a token sequence, or a 2D [img_seq, hidden] tensor missing the batch dimension.

Common situations: Reusing latent tensors directly from a diffusion pipeline that keeps conv layout; forgetting to pack image patches into a sequence; manual inference scripts that skip Flux's latent packing step.

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 huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/bd3b6f2025b51e13. Report an issue: GitHub.