bevyengine/bevy · error

B0003

B0003

Error message

error[B0003]: Could not insert a bundle (of type `{}`) for entity {first_entity} because: {err}. See: https://bevyengine.org/learn/errors/b0003

What it means

This is Bevy error B0003, raised inside World::insert_batch_with_caller, which backs World::insert_batch and World::insert_batch_if_new. It panics when the FIRST entity of the batch cannot be resolved by Entities::get_spawned, i.e. the Entity id is not a currently spawned (alive) entity of this World. Because batch inserts skip per-entity error handling for speed, any dead or foreign id aborts with this error and a link to https://bevyengine.org/learn/errors/b0003.

Source

Thrown at crates/bevy_ecs/src/world/mod.rs:2521

    ) where
        I: IntoIterator,
        I::IntoIter: Iterator<Item = (Entity, B)>,
        B: Bundle<Effect: NoBundleEffect>,
    {
        struct InserterArchetypeCache<'w> {
            inserter: BundleInserter<'w>,
            archetype_id: ArchetypeId,
        }

        let change_tick = self.change_tick();
        let bundle_id = self.register_bundle_info::<B>();

        let mut batch_iter = batch.into_iter();

        if let Some((first_entity, first_bundle)) = batch_iter.next() {
            match self.entities().get_spawned(first_entity) {
                Err(err) => {
                    panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {first_entity} because: {err}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::<B>());
                }
                Ok(first_location) => {
                    let mut cache = InserterArchetypeCache {
                        // SAFETY: we initialized this bundle_id in `register_info`
                        inserter: unsafe {
                            BundleInserter::new_with_id(
                                self,
                                first_location.archetype_id,
                                bundle_id,
                                change_tick,
                            )
                        },
                        archetype_id: first_location.archetype_id,
                    };
                    move_as_ptr!(first_bundle);
                    // SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter, B::Effect: NoBundleEffect
                    unsafe {
                        cache.inserter.insert(

View on GitHub (pinned to 396ca72708)

Solutions

  1. Switch to the fallible API world.try_insert_batch(batch) or try_insert_batch_if_new(batch) and handle the returned TryInsertBatchError.
  2. Filter the batch before inserting: retain only entities for which world.entities().contains(e) (or get_spawned(e).is_ok()) is true.
  3. Re-check ownership/lifecycle: stop holding Entity ids past the despawn point, or verify with world.get_entity_mut(e) before building the batch.
  4. If ids come from another World, remap them (e.g. via the SubEntity/MainEntity mapping in bevy_extract) before batch-inserting.

Example fix

// before
world.insert_batch(batch); // panics if any entity was despawned

// after
let alive: Vec<(Entity, MyBundle)> = batch
    .into_iter()
    .filter(|(e, _)| world.entities().contains(*e))
    .collect();
world.insert_batch(alive);

// or use the fallible version:
if let Err(e) = world.try_insert_batch(batch) {
    warn!("batch insert skipped: {e}");
}
Defensive patterns

Strategy: validation

Validate before calling

let batch: Vec<(Entity, B)> = batch
    .into_iter()
    .filter(|(e, _)| world.entities().contains(*e))
    .collect();
world.insert_batch(batch);

Try / catch

match world.try_insert_batch(batch) {
    Ok(()) => {}
    Err(TryInsertBatchError::EntityDoesNotExist(e)) => warn!("dead entity in batch: {e:?}"),
}

Prevention

When it happens

Trigger: Passing an (Entity, Bundle) pair to world.insert_batch(...) / insert_batch_if_new(...) where the Entity was already despawned, was obtained from a different World (e.g. the render sub-world vs the main world), or is a stale id held across frames after the entity was deleted by another system.

Common situations: Buffering Entity ids in a Vec or event for later batch insertion while another system (or an observer / hook) despawns those entities in between; multi-world setups (extraction) mixing up main-world and sub-world Entity ids; commands deferred across a frame boundary so the target entity is gone by execution time.

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/2628167e0eac52ec. Report an issue: GitHub.