gfx-rs/wgpu · error

source slice length ({src_len}) does not match destination s

Error message

source slice length ({src_len}) does not match destination slice length ({dst_len})

What it means

WriteOnly<[T]>::copy_from_slice panics when the source slice length differs from the length of the destination write-only slice. It deliberately mirrors std's <[_]>::copy_from_slice so misuse fails fast instead of causing a partial or out-of-bounds write into mapped GPU buffer memory.

Source

Thrown at wgpu-types/src/write_only.rs:391

    /// let mut wo = wgpu::WriteOnly::from_mut(buf.as_mut_slice());
    ///
    /// wo.copy_from_slice(&[2, 3, 5, 7, 11]);
    ///
    /// assert_eq!(*buf, [2, 3, 5, 7, 11]);
    #[inline]
    #[track_caller]
    pub fn copy_from_slice(&mut self, src: &[T])
    where
        // Ideally, we want "does not have a destructor" to avoid any need for dropping (which
        // would imply reading) or forgetting the values that write operations overwrite.
        // However, there is no such trait bound and `T: Copy` is the closest approximation.
        T: Copy,
    {
        let src_len = src.len();
        let dst_len = self.len();
        if src_len != dst_len {
            // wording chosen to match <[_]>::copy_from_slice()'s message
            panic!(
                "source slice length ({src_len}) does not match \
                    destination slice length ({dst_len})"
            );
        }

        let src_ptr: *const T = src.as_ptr();
        let dst_ptr: *mut T = self.as_raw_element_ptr().as_ptr();

        // SAFETY:
        // * `src_ptr` is readable because it was constructed from a reference.
        // * `dst_ptr` is writable because that is an invariant of `WriteOnly`.
        // * `dst_ptr` cannot alias `src_ptr` because `self` is exclusive *and*
        //   because `src_ptr` is immutable.
        // * We checked that the byte lengths match.
        // * Lack of data races will be enforced by the type
        unsafe { dst_ptr.copy_from_nonoverlapping(src_ptr, src.len()) }
    }

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. Make the source slice exactly as long as the destination: slice &data[..expected_len] before copying.
  2. Derive the buffer size from data.len() when creating/sizing the buffer or the slice range.
  3. Use chunks to copy data larger than the destination instead of a single copy_from_slice call.

Example fix

// before
let data: Vec<f32> = vec![0.0; 12];
write_slice.copy_from_slice(&data); // slice holds 16 elements
// after
assert_eq!(data.len(), write_slice.len());
write_slice.copy_from_slice(&data[..write_slice.len()]);
Defensive patterns

Strategy: validation

Validate before calling

if src.len() != dst.len() {
    // trim or error out before copying
    return Err("slice length mismatch".into());
}
dst.copy_from_slice(src);

Try / catch

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| dst.copy_from_slice(src)));

Prevention

When it happens

Trigger: Calling buffer_slice.copy_from_slice(&data) where data.len() != the slice's element count — e.g. writing N elements into a slice created with a different size, or forgetting that get_by_mut/slice ranges are element-count based.

Common situations: Uploading uniform/vertex data after resizing the CPU-side Vec (e.g. pushed extra elements, or a struct layout changed), or slicing a buffer by bytes and copying a Vec of elements with mismatched count.

Related errors


AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03). Data as JSON: /api/errors/c6b1df9c188fedfb. Report an issue: GitHub.