bevyengine/bevy · error · WriteBufferRangeError

RangeBiggerThanBuffer

RangeBiggerThanBuffer

Error message

the range is bigger than the capacity of the buffer

What it means

WriteBufferRangeError::RangeBiggerThanBuffer is returned by BufferVec/RawBufferVec::write_buffer_range when the requested range end exceeds the GPU buffer's capacity (item_size * capacity, checked at buffer_vec.rs:204). The CPU-side values vector grew past what was reserved on the GPU, so the requested bytes cannot be uploaded into the existing buffer.

Source

Thrown at crates/bevy_render/src/render_resource/buffer_vec.rs:980

impl<T> PartialBufferVec<T>
where
    T: NoUninit + Default,
{
    /// Pushes `count` copies of `T::default` to the array.
    pub fn push_multiple_init(&mut self, count: usize) -> usize {
        debug_assert_eq!(self.uninit_element_count, 0);
        let index = self.values.len();
        self.values.extend(iter::repeat_n(T::default(), count));
        index
    }
}

/// Error returned when `write_buffer_range` fails
///
/// See [`RawBufferVec::write_buffer_range`] [`BufferVec::write_buffer_range`]
#[derive(Debug, Eq, PartialEq, Copy, Clone, Error)]
pub enum WriteBufferRangeError {
    #[error("the range is bigger than the capacity of the buffer")]
    RangeBiggerThanBuffer,
    #[error("the gpu buffer is not initialized")]
    BufferNotInitialized,
    #[error("there are no values to upload")]
    NoValuesToUpload,
}

#[inline]
#[cfg_attr(
    not(feature = "type_label_buffers"),
    expect(
        clippy::extra_unused_type_parameters,
        reason = "conditional compilation"
    )
)]
pub(crate) fn make_buffer_label<'a, T>(label: &'a Option<String>) -> Option<&'a str> {
    #[cfg(feature = "type_label_buffers")]
    if label.is_none() {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Call vec.reserve(new_capacity, render_device) before writing once len exceeds capacity - note reserving reallocates the GPU buffer (values is the source of truth, so re-upload the full range).
  2. Grow capacity geometrically (e.g. double it) to avoid reallocating every frame.
  3. Double-check the range is expressed in element indices and stays within the reserved capacity.

Example fix

// before
vec.push(instance);
vec.write_buffer_range(queue, 0..vec.len())?; // Err: len grew past GPU capacity

// after
if vec.len() > vec.capacity() {
    vec.reserve(vec.len().max(vec.capacity() * 2), render_device);
}
vec.write_buffer_range(queue, 0..vec.len())?;
Defensive patterns

Strategy: validation

Validate before calling

if vec.len() > vec.capacity() {
    vec.reserve(vec.len().max(vec.capacity() * 2), render_device); // grow GPU capacity
}
vec.write_buffer_range(queue, 0..vec.len())?;

Try / catch

match vec.write_buffer_range(queue, 0..vec.len()) {
    Err(WriteBufferRangeError::RangeBiggerThanBuffer) => {
        vec.reserve(vec.len().max(vec.capacity() * 2), render_device);
        vec.write_buffer_range(queue, 0..vec.len())?; // retry after reserve
    }
    other => other?,
}

Prevention

When it happens

Trigger: Pushing/extending values beyond the previously reserved GPU capacity, then calling write_buffer_range over a range that covers the new elements without calling reserve() first; or computing the range from a stale/incorrect length.

Common situations: Per-frame growth of instance/uniform/light buffers where capacity was reserved once at startup; clear()-then-regrow flows that forget to re-reserve; capacity computed from the wrong unit (elements vs bytes).

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/2effd45558ff8642. Report an issue: GitHub.