tracel-ai/burn · error
ndarray scatter_nd requires contiguous values
Error message
ndarray scatter_nd requires contiguous values
What it means
scatter_nd writes slices of `values` into `data` at positions given by `indices`. The ndarray backend needs both arrays as flat contiguous buffers, so it calls `as_slice()`, which returns None for non-contiguous arrays (e.g. views with strides, broadcast arrays, or slices of a larger array) and this expect() panics. This is a backend implementation constraint, not a user-facing error message.
Source
Thrown at crates/burn-ndarray/src/ops/base.rs:330
// Number of index tuples = product of batch dims (first M-1 dims of indices)
let num_indices: usize = idx_shape[..m - 1].iter().product();
// Size of each slice to scatter = product of data.shape[K..]
let slice_size: usize = data_shape[k..].iter().product();
let mut output = data.into_owned();
let output_flat = output
.as_slice_mut()
.expect("ndarray scatter_nd requires contiguous data");
// Flatten indices to [num_indices, K]
let idx_flat = indices
.as_slice()
.expect("ndarray scatter_nd requires contiguous indices");
// Flatten values to [num_indices, slice_size]
let val_flat = values
.as_slice()
.expect("ndarray scatter_nd requires contiguous values");
let strides: Vec<usize> = {
let mut s = vec![0usize; k];
if k > 0 {
s[k - 1] = slice_size;
for i in (0..k - 1).rev() {
s[i] = s[i + 1] * data_shape[i + 1];
}
}
s
};
for n in 0..num_indices {
// Compute flat base offset from the K-dimensional index
let mut base_offset = 0usize;
for j in 0..k {
let idx_val = idx_flat[n * k + j].elem::<i64>() as usize;
base_offset += idx_val * strides[j];View on GitHub (pinned to d16f7ba2ed)
Solutions
- Call .contiguous() (or float_into_contiguous / .into_owned()) on the values tensor before scatter, or restructure so values comes from a contiguous op (e.g. cat, from_data)
- Check for intervening slice/permute/broadcast ops on values and insert an explicit copy
- If hitting this from library-internal code, report/fix the op to call into_owned() before as_slice(), as gather ops do
Example fix
// before let values = tensor_slice.transpose(); let out = data.scatter(indices, values); // after let values = tensor_slice.transpose().contiguous(); let out = data.scatter(indices, values);
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_contiguous<E: burn_ndarray::FloatElement>(t: &Tensor<NdArray<E>, D>) -> Tensor<NdArray<E>, D> {
// force materialization of any zero-stride/strided view
t.clone().float_into_contiguous() // or t.clone().contiguous() depending on dtype
}
// call before: let out = data.scatter(indices, ensure_contiguous(&values)); Prevention
- Call .contiguous() on tensors produced by slice/transpose/broadcast before scatter
- Avoid passing broadcast-expanded tensors as scatter values
- Keep scatter operands as results of contiguous ops (from_data, cat, matmul)
- In tests, assert tensor.to_data() round-trips without panic on your pipeline shapes
When it happens
Trigger: Calling Tensor::scatter (scatter_nd) on the ndarray backend with a `values` tensor that is a non-contiguous view - typically a slice, permuted/transposed view, or broadcasted tensor - so that ArrayD::as_slice() yields None. Also happens if the tensor was produced by an op returning a zero-stride view that was never copied into owned memory.
Common situations: Scattering into a tensor obtained from slice/select operations without calling .into_owned() or .contiguous() first; combining scatter with transpose/permute in a data-prep pipeline; passing a broadcast-expanded tensor as values.
Related errors
- ndarray gather_nd requires contiguous data
- ndarray gather_nd requires contiguous indices
- float_scatter: unsupported dtype {:?}
- int_scatter: unsupported dtype {:?}
- Invalid dimension: the shape of the index tensor should be t
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/823cd3c4d928539f.
Report an issue: GitHub.