huggingface/candle · error

axis {axis} is too large, tensor rank {rank}

Error message

axis {axis} is too large, tensor rank {rank}

What it means

Tensor::normalize_axis converts a possibly-negative axis into a concrete dimension index. If the given axis (already assumed non-negative when this branch fires, or too large after other checks) is >= the tensor's rank, there is no matching dimension, so it bails with the axis value and rank. In this codepath it fires when 0 <= axis and rank <= axis.

Source

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

    /// Unique key for this tensor's storage. Equal keys mean the tensors share the same allocation.
    #[inline]
    pub(crate) fn storage_key(&self) -> usize {
        let lock: &RwLock<Storage> = self.storage.as_ref();
        std::ptr::from_ref(lock).addr()
    }

    /// Check if two tensors share the same underlying allocation.
    #[inline]
    pub(crate) fn same_storage(&self, rhs: &Self) -> bool {
        self.storage_key() == rhs.storage_key()
    }

    /// Normalize a 'relative' axis value: positive values are kept, negative
    /// values means counting the dimensions from the back.
    pub fn normalize_axis(&self, axis: i64) -> Result<usize> {
        let rank = self.rank() as i64;
        if rank <= axis {
            bail!("axis {axis} is too large, tensor rank {rank}")
        } else if 0 <= axis {
            Ok(axis as usize)
        } else {
            let naxis = rank + axis;
            if naxis < 0 {
                bail!("axis {axis} is too small, tensor rank {rank}")
            }
            Ok(naxis as usize)
        }
    }

    /// Returns a lower triangular matrix of ones of size n by n.
    pub fn tril2(n: usize, dtype: DType, device: &Device) -> Result<Self> {
        let t = Tensor::arange(0u32, n as u32, device)?;
        let t1 = t.reshape((1, n))?.broadcast_as((n, n))?;
        let t2 = t.reshape((n, 1))?.broadcast_as((n, n))?;
        t1.le(&t2)?.to_dtype(dtype)
    }

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Verify the tensor's rank and use axis < rank (or axis in [-rank, -1] for negative indexing)
  2. Print/inspect the tensor shape before the call and correct the axis constant
  3. Guard the call site: if rank <= axis { adjust or error }

Example fix

// before
let idx = t.normalize_axis(3)?; // rank 2 tensor
// after
let idx = t.normalize_axis((3 + t.rank() as i64) % t.rank() as i64)?; // or use axis 1
Defensive patterns

Strategy: validation

Validate before calling

let axis: i64 = 3;
if axis >= t.rank() as i64 {
    panic!("axis {} >= rank {}", axis, t.rank());
}

Try / catch

let idx = t.normalize_axis(axis)
    .map_err(|e| { log::warn!("axis {} invalid for rank {}", axis, t.rank()); e })?;

Prevention

When it happens

Trigger: Calling tensor.normalize_axis(3) on a rank-2 tensor, or passing axis >= rank to APIs that route through normalize_axis (e.g. ops taking axis: i64).

Common situations: Porting PyTorch code where an axis constant assumed a different number of dims; off-by-one from forgetting batch dims were squeezed; framework code passing axis=0 to a 0-dim (scalar) tensor.

Related errors


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