huggingface/candle · error

dimension mismatch in permute, tensor {:?}, dims: {:?}

Error message

dimension mismatch in permute, tensor {:?}, dims: {:?}

What it means

Tensor::permute reorders existing dimensions and therefore requires the supplied dims to be a valid permutation of 0..rank — same length as the rank, with every index 0..rank appearing exactly once. Anything else (repeated indices, out-of-range indices, wrong count) triggers this bail, which includes the tensor's dims and the offending dims for debugging.

Source

Thrown at candle-core/src/tensor.rs:2329

    /// Returns a tensor with the same data as the input where the dimensions have been permuted.
    /// dims must be a permutation, i.e. include each dimension index exactly once.
    ///
    /// ```rust
    /// use candle_core::{Tensor, Device};
    /// let tensor = Tensor::arange(0u32, 120u32, &Device::Cpu)?.reshape((2, 3, 4, 5))?;
    /// assert_eq!(tensor.dims(), &[2, 3, 4, 5]);
    /// let tensor = tensor.permute((2, 3, 1, 0))?;
    /// assert_eq!(tensor.dims(), &[4, 5, 3, 2]);
    /// # Ok::<(), candle_core::Error>(())
    /// ```
    pub fn permute<D: Dims>(&self, dims: D) -> Result<Tensor> {
        let dims = dims.to_indexes(self.shape(), "permute")?;
        // O(n^2) permutation check but these arrays are small.
        let is_permutation =
            dims.len() == self.rank() && (0..dims.len()).all(|i| dims.contains(&i));
        if !is_permutation {
            bail!(
                "dimension mismatch in permute, tensor {:?}, dims: {:?}",
                self.dims(),
                dims
            )
        }
        let op = BackpropOp::new1(self, |t| Op::Permute(t, dims.clone()));
        let tensor_ = Tensor_ {
            id: TensorId::new(),
            storage: self.storage.clone(),
            layout: self.layout.permute(&dims)?,
            op,
            is_variable: false,
            dtype: self.dtype,
            device: self.device.clone(),
        };
        Ok(Tensor(Arc::new(tensor_)))
    }

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Verify dims is a permutation of 0..t.rank(): same length, no duplicates, all indices < rank.
  2. For a simple two-dimension swap, use t.transpose(d1, d2) instead of permute.
  3. Print t.dims() and check your permutation against the actual rank.
  4. For NHWC<->NCHW on 4-D tensors use the standard permutations: [0,3,1,2] and [0,2,3,1].

Example fix

// before
let out = img.permute(&[0, 2, 1])?; // img is rank 4 -> error
// after
let out = img.permute(&[0, 2, 3, 1])?; // valid permutation of 0..4
Defensive patterns

Strategy: validation

Validate before calling

let dims = [0usize, 2, 3, 1];
let r = t.rank();
let is_perm = dims.len() == r && (0..r).all(|i| dims.contains(&i));
if !is_perm {
    return Err(anyhow!("invalid permutation {:?} for rank {}", dims, r));
}
let out = t.permute(dims)?;

Try / catch

match t.permute(dims) {
    Ok(x) => x,
    Err(e) if e.to_string().contains("dimension mismatch in permute") => {
        eprintln!("rank={}, attempted dims={:?}", t.rank(), dims);
        return Err(e.into());
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling t.permute(&[0, 2, 1]) on a tensor whose rank doesn't match the dims length; passing duplicate indices like [0,1,1]; using out-of-range indices like [0,3,2] on a rank-3 tensor; confusing permute (permutation of dims) with transpose (swap of two dims).

Common situations: Porting NumPy/PyTorch code with hardcoded permutations to a differently-shaped tensor; off-by-one dims in NHWC<->NCHW conversions; calling permute instead of transpose for a simple two-dim swap.

Related errors


AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/cc6baf9d49a9bfb2. Report an issue: GitHub.