bevyengine/bevy · critical
`Range` provided to `render_range()` is out of bounds
Error message
`Range` provided to `render_range()` is out of bounds
What it means
RenderPhase::render_range (mod.rs:1991) panics when the supplied range cannot index self.items: items.get_range(range) returned None because the range is out of bounds for the current item count. It is a hard precondition - the caller must pass a range that fits within 0..items.len() for the phase as it exists right now.
Source
Thrown at crates/bevy_render/src/render_phase/mod.rs:1990
render_pass: &mut TrackedRenderPass<'w>,
world: &'w World,
view: Entity,
) -> Result<(), DrawError> {
self.render_range(render_pass, world, view, ..)
}
/// Renders all [`PhaseItem`]s in the provided `range` (based on their index in `self.items`) using their corresponding draw functions.
pub fn render_range<'w>(
&self,
render_pass: &mut TrackedRenderPass<'w>,
world: &'w World,
view: Entity,
range: impl RangeBounds<usize>,
) -> Result<(), DrawError> {
let items = self
.items
.get_range(range)
.expect("`Range` provided to `render_range()` is out of bounds");
let draw_functions = world.resource::<DrawFunctions<I>>();
let mut draw_functions = draw_functions.write();
draw_functions.prepare(world);
let mut index = 0;
while index < items.len() {
let item = &items[index];
let batch_range = item.batch_range();
if batch_range.is_empty() {
index += 1;
} else {
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
draw_function.draw(world, render_pass, view, item)?;
index += batch_range.len();
}
}
Ok(())View on GitHub (pinned to 221e52ae32)
Solutions
- Clamp the range to the current length before calling: 0..n.min(phase.items.len()).
- Recompute any cached item counts after sorting/filtering/clearing the phase.
- Use RenderPhase::render() instead when you do not need sub-ranges.
Example fix
// before let end = cached_item_count; // may be stale after the phase was rebuilt render_phase.render_range(&mut pass, &world, view, 0..end)?; // after let end = cached_item_count.min(render_phase.items.len()); render_phase.render_range(&mut pass, &world, view, 0..end)?;
Defensive patterns
Strategy: validation
Validate before calling
// Clamp before calling render_range: let end = requested_end.min(render_phase.items.len()); let start = requested_start.min(end); render_phase.render_range(&mut pass, &world, view, start..end)?;
Prevention
- Never reuse an item count captured before sorting, filtering, or clearing the phase.
- Compute chunk ranges from the phase's current items.len() each frame.
- Prefer render() over render_range() when full-phase rendering suffices.
When it happens
Trigger: Calling render_range(pass, world, view, 0..n) with n greater than phase.items.len() - typically a count cached from before the phase was sorted, compacted, or cleared, or chunk-splitting arithmetic that overshoots.
Common situations: Custom render nodes splitting a phase into chunks (stereo/XR per-eye slices); lengths captured across frames while the phase was rebuilt; off-by-one errors after filtering items out of the phase.
Related errors
- Tried to read past the end of the buffer (start: {start}, si
- Cannot call `ReflectComponent::reflect_mut` on component {na
- Cannot call `ReflectComponent::reflect_unchecked_mut` on com
- component should represent a type.
- `{type_path}` should be registered in type registry via `App
AI-assisted analysis of bevyengine/bevy@221e52ae32 (2026-08-20).
Data as JSON: /api/errors/bfa6e87f06837708.
Report an issue: GitHub.