{"record":{"id":"a01fb25c666b5f6d","repo":"tracel-ai/burn","slug":"gather-nd-shape-mismatch","errorCode":null,"errorMessage":"gather_nd: shape mismatch","messagePattern":"gather_nd: shape mismatch","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-ndarray/src/ops/base.rs","lineNumber":445,"sourceCode":"        };\n\n        let mut output_vec: Vec<E> = vec![0.elem::<E>(); out_total];\n\n        for n in 0..num_indices {\n            let mut base_offset = 0usize;\n            for j in 0..k {\n                let idx_val = idx_flat[n * k + j].elem::<i64>() as usize;\n                base_offset += idx_val * strides[j];\n            }\n\n            let out_offset = n * slice_size;\n            output_vec[out_offset..(out_offset + slice_size)]\n                .copy_from_slice(&data_flat[base_offset..(base_offset + slice_size)]);\n        }\n\n        let out_shape = Shape::from(out_shape_vec);\n        let output = ArrayD::from_shape_vec(out_shape.as_slice(), output_vec)\n            .expect(\"gather_nd: shape mismatch\");\n\n        output.into_shared()\n    }\n\n    fn gather_batch_size(shape_tensor: &[usize], shape_indices: &[usize]) -> usize {\n        let ndims = shape_tensor.num_dims();\n        let mut batch_size = 1;\n\n        for i in 0..ndims - 1 {\n            if shape_tensor[i] != shape_indices[i] {\n                panic!(\n                    \"Unsupported dimension, only the last dimension can differ: Tensor {:?} Index \\\n                     {:?}\",\n                    shape_tensor, shape_indices\n                );\n            }\n            batch_size *= shape_indices[i];\n        }","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-ndarray/src/ops/base.rs#L427-L463","documentation":"After collecting all slices, gather_nd rebuilds the output ArrayD via from_shape_vec with the computed out_shape (idx_shape[..m-1] + data_shape[k..]). If the accumulated output_vec length does not equal num_indices * slice_size, from_shape_vec returns Err and this expect() panics - i.e. the computed output shape is inconsistent with the number of elements produced.","triggerScenarios":"Calling gather_nd where rank/index-dim parameters (k slices from indices last dim, m leading index dims) produce an out_total that doesn't match the filled output_vec; typically caused by indices whose shape doesn't match data's rank, or index values out of range writing past the intended region (indices out of bounds would first panic elsewhere; here the mismatch is shape arithmetic, e.g. empty index tensor edge cases or k/m mis-derivation).","commonSituations":"ONNX GatherND graphs with unusual index ranks; calling gather with indices whose last dimension exceeds data rank; zero-size index tensors where shape computation yields 0 elements but non-zero shape.","solutions":["Verify indices rank: indices.dims().last() must be <= data.dims().len(); expected output shape = indices.dims()[..-1] + data.dims()[k..]","Validate all index values are within bounds of the corresponding data dimension before calling","Test with small known shapes to confirm k (slice depth) semantics; slice_size = product of data_shape[k..], num_indices = product of idx_shape[..m-1]"],"exampleFix":"// before\nlet idx = Tensor::<Cpu, 3>::from_data(...); // last dim 3, data rank 2\nlet out = data.gather(idx); // k > data rank -> inconsistent shape\n// after\nlet idx = Tensor::<Cpu, 2>::from_data(...); // last dim <= data rank\nlet out = data.gather(idx);","handlingStrategy":"validation","validationCode":"// before calling gather, verify shape contract:\nfn check_gather_shapes(data_dims: &[usize], idx_dims: &[usize]) -> Result<Vec<usize>, String> {\n    let k = *idx_dims.last().ok_or(\"indices must be non-empty rank\")?;\n    if k > data_dims.len() { return Err(format!(\"indices last dim {} exceeds data rank {}\", k, data_dims.len())); }\n    let slice_size: usize = data_dims[k..].iter().product();\n    let num_indices: usize = idx_dims[..idx_dims.len()-1].iter().product();\n    Ok(idx_dims[..idx_dims.len()-1].iter().cloned().chain(data_dims[k..].iter().cloned()).collect())\n    // expected output has num_indices * slice_size elements\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure indices' last dim <= data rank; output shape = idx_dims[..-1] + data_dims[k..]","Validate all index values are in-bounds for their data dimension","Test gather with tiny known shapes when changing rank conventions","For ONNX GatherND, confirm k semantics match burn's (slices = last index dim)"],"tags":["rust","ndarray","panic","gather","shape-mismatch"],"backgroundTag":"tensor-shape-mismatch","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}