{"record":{"id":"171e91763bcc4f9d","repo":"huggingface/candle","slug":"axis-axis-is-too-small-tensor-rank-rank","errorCode":null,"errorMessage":"axis {axis} is too small, tensor rank {rank}","messagePattern":"axis (.+?) is too small, tensor rank (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-core/src/tensor.rs","lineNumber":2808,"sourceCode":"\n    /// Check if two tensors share the same underlying allocation.\n    #[inline]\n    pub(crate) fn same_storage(&self, rhs: &Self) -> bool {\n        self.storage_key() == rhs.storage_key()\n    }\n\n    /// Normalize a 'relative' axis value: positive values are kept, negative\n    /// values means counting the dimensions from the back.\n    pub fn normalize_axis(&self, axis: i64) -> Result<usize> {\n        let rank = self.rank() as i64;\n        if rank <= axis {\n            bail!(\"axis {axis} is too large, tensor rank {rank}\")\n        } else if 0 <= axis {\n            Ok(axis as usize)\n        } else {\n            let naxis = rank + axis;\n            if naxis < 0 {\n                bail!(\"axis {axis} is too small, tensor rank {rank}\")\n            }\n            Ok(naxis as usize)\n        }\n    }\n\n    /// Returns a lower triangular matrix of ones of size n by n.\n    pub fn tril2(n: usize, dtype: DType, device: &Device) -> Result<Self> {\n        let t = Tensor::arange(0u32, n as u32, device)?;\n        let t1 = t.reshape((1, n))?.broadcast_as((n, n))?;\n        let t2 = t.reshape((n, 1))?.broadcast_as((n, n))?;\n        t1.le(&t2)?.to_dtype(dtype)\n    }\n\n    /// Returns an upper triangular matrix of ones of size n by n.\n    pub fn triu2(n: usize, dtype: DType, device: &Device) -> Result<Self> {\n        let t = Tensor::arange(0u32, n as u32, device)?;\n        let t1 = t.reshape((1, n))?.broadcast_as((n, n))?;\n        let t2 = t.reshape((n, 1))?.broadcast_as((n, n))?;","sourceCodeStart":2790,"sourceCodeEnd":2826,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-core/src/tensor.rs#L2790-L2826","documentation":"Tensor::normalize_axis supports negative axes by counting from the back: naxis = rank + axis. If the negative axis is so negative that naxis < 0 (i.e. axis < -rank), it does not address any dimension, so the method bails reporting the axis and rank.","triggerScenarios":"Calling tensor.normalize_axis(-4) on a rank-3 tensor, or passing an axis < -rank to APIs using normalize_axis.","commonSituations":"Hardcoded negative axis like -1 applied after the tensor was squeezed to fewer dims; config-driven axis values not validated against the actual rank; batched models where an extra dim changes what -2 refers to.","solutions":["Ensure axis is in the valid range -rank..=rank-1 before calling","Clamp or recompute the axis from the actual tensor rank at runtime","Add a debug_assert/log of t.rank() near the call site"],"exampleFix":"// before\nlet idx = t.normalize_axis(-2)?; // rank 1 tensor -> naxis = -1\n// after\nlet axis = -2i64;\nassert!(axis >= -(t.rank() as i64));\nlet idx = t.normalize_axis(axis)?;","handlingStrategy":"validation","validationCode":"let axis: i64 = -2;\nif axis < -(t.rank() as i64) {\n    panic!(\"axis {} too negative for rank {}\", axis, t.rank());\n}","typeGuard":null,"tryCatchPattern":"let idx = t.normalize_axis(axis)\n    .with_context(|| format!(\"axis {} invalid for rank {}\", axis, t.rank()))?;","preventionTips":["Validate negative axes against -rank at call sites","Avoid hardcoded negative indices in configs; resolve them after shapes are known","Re-derive axes whenever a squeeze/reshape changes rank"],"tags":["rust","candle","axis","negative-index"],"backgroundTag":"axis-out-of-range","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}