bevyengine/bevy · error · DrawError

View entity not found

Error message

View entity not found

What it means

DrawError::ViewEntityNotFound is returned by RenderCommandState::draw (draw.rs:333) when the view entity passed to RenderPhase::render/render_range is not spawned in the render world (QueryEntityError::NotSpawned from the command's ViewQuery). The entity handle used for drawing refers to an entity that does not exist.

Source

Thrown at crates/bevy_render/src/render_phase/draw.rs:50

    fn prepare(&mut self, world: &'_ World) {}

    /// Draws a [`PhaseItem`] by issuing zero or more `draw` calls via the [`TrackedRenderPass`].
    fn draw<'w>(
        &mut self,
        world: &'w World,
        pass: &mut TrackedRenderPass<'w>,
        view: Entity,
        item: &P,
    ) -> Result<(), DrawError>;
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum DrawError {
    #[error("Failed to execute render command {0:?}")]
    RenderCommandFailure(&'static str),
    #[error("Failed to get execute view query")]
    InvalidViewQuery,
    #[error("View entity not found")]
    ViewEntityNotFound,
}

/// Stores all [`Draw`] functions for the [`PhaseItem`] type.
///
/// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s.
pub struct DrawFunctionsInternal<P: PhaseItem> {
    pub draw_functions: Vec<Box<dyn Draw<P>>>,
    pub indices: TypeIdHashMap<DrawFunctionId>,
}

impl<P: PhaseItem> DrawFunctionsInternal<P> {
    /// Prepares all draw function. This is called once and only once before the phase begins.
    pub fn prepare(&mut self, world: &World) {
        for function in &mut self.draw_functions {
            function.prepare(world);
        }
    }

View on GitHub (pinned to 396ca72708)

Solutions

  1. Check the entity exists in the render world before rendering (world.entities().contains(view)).
  2. Do not cache view entities across frames; re-query the view each render.
  3. Perform camera/entity despawns via Commands in the main schedule rather than during extract/render.
  4. Catch the error and skip the frame instead of propagating a hard failure.

Example fix

// before
render_phase.render(&mut render_pass, &render_world, cached_view_entity)?;

// after
if !render_world.entities().contains(cached_view_entity) {
    warn!("view entity {cached_view_entity:?} gone; skipping frame");
    return Ok(());
}
let _ = render_phase.render(&mut render_pass, &render_world, cached_view_entity);
Defensive patterns

Strategy: validation

Validate before calling

if !render_world.entities().contains(view_entity) {
    // despawned or never existed in the render world
    return Ok(());
}

Try / catch

match render_phase.render(&mut pass, &render_world, view) {
    Err(DrawError::ViewEntityNotFound) => warn!("view {view:?} despawned before render"),
    Err(other) => error!("{other:?}"),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: Calling render_phase.render(&mut pass, world, view_entity) with a view Entity that was despawned, never existed in the render world, or is a main-world entity handle used against the render world; stale view handles cached across frames.

Common situations: Cameras despawned between extraction and render; custom render nodes caching the view entity from a previous frame; systems running during app teardown or after render-world clearing; mixing up main-world and render-world entity ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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