bevyengine/bevy · critical

cannot reserve a larger AlignedVec

Error message

cannot reserve a larger AlignedVec

What it means

`AlignedVec` is bevy_platform's alignment-aware vector (used for GPU-friendly storage in no_std contexts). `reserve`/`push`/`extend_from_slice` funnel growth through the `#[cold]` `do_reserve`, which computes `len + additional` with `checked_add`; if the sum overflows `usize`, the `.expect("cannot reserve a larger AlignedVec")` at crates/bevy_platform/src/collections/aligned_vec.rs:436 panics.

Source

Thrown at crates/bevy_platform/src/collections/aligned_vec.rs:436

        let remaining = self.cap.wrapping_sub(self.len);
        if additional > remaining {
            self.do_reserve(additional);
        }
    }

    /// Extend capacity after `reserve` has found it's necessary.
    ///
    /// Actually performing the extension is in this separate function marked
    /// `#[cold]` to hint to compiler that this branch is not often taken.
    /// This keeps the path for common case where capacity is already sufficient
    /// as fast as possible, and makes `reserve` more likely to be inlined.
    /// This is the same trick that Rust's `Vec::reserve` uses.
    #[cold]
    fn do_reserve(&mut self, additional: usize) {
        let new_cap = self
            .len
            .checked_add(additional)
            .expect("cannot reserve a larger AlignedVec");
        // SAFETY: `do_reserve` is only called when capacity grows
        unsafe { self.grow_capacity_to(new_cap) };
    }

    /// Grows total capacity of vector to `new_cap` or more.
    ///
    /// Capacity after this call will be `new_cap` rounded up to next power of
    /// 2, unless that would exceed maximum capacity, in which case capacity
    /// is capped at the maximum.
    ///
    /// This is same growth strategy used by `reserve`, `push` and
    /// `extend_from_slice`.
    ///
    /// Usually the safe methods `reserve` or `reserve_exact` are a better
    /// choice. This method only exists as a micro-optimization for very
    /// performance-sensitive code where the calculation of capacity
    /// required has already been performed, and you want to avoid doing it
    /// again.

View on GitHub (pinned to 396ca72708)

Solutions

  1. Debug where `additional` comes from — the panic means `len + additional` exceeds usize::MAX, which needs a ~2^64 request on 64-bit targets
  2. Validate sizes read from files/network before reserving (reject when total byte size exceeds `isize::MAX`)
  3. Fix the arithmetic: use `usize`/`u64` with `checked_*` math instead of `as usize` casts from signed values

Example fix

// before: negative/trusting count cast to usize
let count = header.count as usize; // header.count: i32, could be negative -> huge usize
vec.reserve(count);

// after: validate before reserving
let count = usize::try_from(header.count).map_err(|_| InvalidHeader)?;
if count > vec.max_capacity().saturating_sub(vec.len()) {
    return Err(InvalidHeader);
}
vec.reserve(count);
Defensive patterns

Strategy: validation

Validate before calling

fn safe_reserve(vec: &AlignedVec<T>, additional: usize) -> bool {
    additional <= usize::MAX - vec.len()
        && vec.len() + additional <= vec.max_capacity()
}

Prevention

When it happens

Trigger: Calling `reserve(additional)` (directly or via `push`/`extend_from_slice` growth) where `additional > usize::MAX - len` — in practice almost always a size-computation bug upstream: a negative count cast with `as usize`, an underflowed subtraction, or untrusted asset data whose header declares a near-`u64::MAX` element count.

Common situations: Asset parsers reserving from file headers; index/length math that mixed signed and unsigned types; fuzzing or corrupted input files feeding absurd sizes into a builder that uses AlignedVec.

Related errors


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