Skip to content

Panic when using spawn command within Trigger<OnRemove> observer #15439

Closed
@swejk

Description

@swejk

Bevy version

0.14.2

What you did

Run this code:


#[derive(Component)]
struct TestRemoveComp;

#[derive(Component)]
struct CoundownTimer {
    pub start: Instant,
    pub duration: Duration,
}

#[derive(Component)]
struct TestSpawnComp;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, |mut commands: Commands| {
            commands.spawn((
                TestRemoveComp,
                CoundownTimer {
                    start: Instant::now(),
                    duration: Duration::from_secs_f32(1.),
                },
            ));
        })
        .add_systems(
            Update,
            |mut commands: Commands, query: Query<(Entity, &CoundownTimer)>| {
                for (entity, timer) in &mut query.iter() {
                    if timer.start.elapsed() > timer.duration {
                        commands.entity(entity).despawn();
                    }
                }
            },
        )
        .observe(
            |_: Trigger<OnRemove, TestRemoveComp>, mut commands: Commands| {
                commands.spawn(TestSpawnComp);
            },
        )
        .run();
    }

What went wrong

App panicked.
I am noticing this behaviour only when Commands::spawn is issued within Trigger<OnRemove> observer. Commands::insert and Commands::add works correctly in this context.

thread 'main' panicked at C:\Users\User\.cargo\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.14.0\src\entity\mod.rs:582:9:
flush() needs to be called before this operation is legal
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic when applying buffers for system `test::main::{{closure}}`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

Additional information

As a workaround I am spawning from dedicated Command instead of spawning directly.

...
 .observe(
            |_: Trigger<OnRemove, TestRemoveComp>, mut commands: Commands| {
                commands.add(TriggerOnRemoveSpawnWorkaround {bundle: TestSpawnComp});
            },
        )

pub struct TriggerOnRemoveSpawnWorkaround<B: Bundle> {
    pub bundle: B,
}

impl <B> Command for TriggerOnRemoveSpawnWorkaround<B> 
where B: Bundle {
    fn apply(self, world: &mut bevy::prelude::World) {
        world.spawn(self.bundle);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behaviorP-CrashA sudden unexpected crashS-Needs-InvestigationThis issue requires detective work to figure out what's going wrong

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions