tracel-ai/burn · error

The shapes should be broadcastable

Error message

The shapes should be broadcastable

What it means

expand broadcasts a tensor to a target shape using ndarray's broadcast(), which only succeeds when each target dimension equals the source dimension or is 1-expandable (source dim is 1, or the dim is prepended). If the given shape is incompatible, ndarray returns Err and this expect() panics.

Solutions

  1. Ensure each source dim is either 1 or equal to the corresponding target dim (right-aligned), and target rank >= source rank
  2. Check the rank of the input at runtime; reshape/insert dims before expanding
  3. Use repeat(dim, n) for cases where you want to replicate along one axis of an existing dim

Example fix

// before
let x: Tensor<NdArray, 2> = ...; // dims [3, 1]
x.expand([2, 5]); // 3 != 5 -> panic
// after
let x: Tensor<NdArray, 2> = ...; // dims [3, 1]
x.expand([3, 5]); // leading dims must match or be 1
Defensive patterns

Strategy: validation

Validate before calling

fn can_broadcast_to(src: &[usize], dst: &[usize]) -> bool {
    dst.len() >= src.len()
        && dst[dst.len()-src.len()..]
            .iter()
            .zip(src)
            .all(|(d, s)| *d == *s || *s == 1)
}
// if !can_broadcast_to(&x.dims(), &[3, 5]) { /* fix shape */ }

Prevention

When it happens

Trigger: Calling Tensor::expand / Tensor::repeat with a shape whose trailing dims don't match the source (source dim != 1 and != target dim), or a target shape with fewer dims than the source tensor.

Common situations: Hard-coded expand shapes that assume a different input rank (e.g. after a squeeze/reshape change); expanding a [B, C, H, W] tensor to [B, C', H, W] where C' != C and C != 1; ONNX Expand nodes with mismatched shape inputs.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/c9da79987221f8d8. Report an issue: GitHub.

Appendix: source

Thrown at crates/burn-ndarray/src/ops/base.rs:554

        slices
    }

    pub fn swap_dims(mut tensor: SharedArray<E>, dim1: usize, dim2: usize) -> SharedArray<E> {
        tensor.swap_axes(dim1, dim2);

        tensor
    }

    pub fn permute(tensor: SharedArray<E>, axes: &[usize]) -> SharedArray<E> {
        tensor.permuted_axes(axes.into_dimension())
    }

    /// Broadcasts the tensor to the given shape
    pub(crate) fn expand(tensor: SharedArray<E>, shape: Shape) -> SharedArray<E> {
        tensor
            .broadcast(shape.into_dimension())
            .expect("The shapes should be broadcastable")
            // need to convert view to owned array because NdArrayTensor expects owned array
            // and try_into_owned_nocopy() panics for broadcasted arrays (zero strides)
            .into_owned()
            .into_shared()
    }

    pub fn flip(tensor: SharedArray<E>, axes: &[usize]) -> SharedArray<E> {
        let slice_items: Vec<_> = (0..tensor.shape().num_dims())
            .map(|i| {
                if axes.contains(&i) {
                    SliceInfoElem::Slice {
                        start: 0,
                        end: None,
                        step: -1,
                    }
                } else {
                    SliceInfoElem::Slice {
                        start: 0,

View on GitHub (pinned to d16f7ba2ed)