Skip to content

Archetype bug panics when calling EntityWorldMut::observe several times before calling EntityWorldMut::insert #18844

Open
@Jarten0

Description

@Jarten0

Bevy version

v0.15.3

Context

I have a command that spawns an entity in a fairly complex process, making use of exclusive world access and EntityWorldMut to optionally insert components covering a moderate spread of functionality, and I added a secondary EntityWorldMut::observe call in the midst of the function only to find that the game would throw a weird subtract underflow error @ bevy_ecs-0.15.3/src/archetype.rs:587:38:. Through tracing, I found out that the program hadn't panic'd when calling observe, but instead later on in my function when calling EntityWorldMut::insert. So I wrote out what I thought was the issue in the following.

Source code for reproducing issue

use bevy::prelude::*;

#[test]
fn observe_underflow() {
    println!("Started test");

    let mut world = World::new();

    let mut entity: EntityWorldMut = world.spawn_empty();

    println!("Spawned empty entity");

    entity.observe(|_trigger: Trigger<Foo>| ());
    entity.observe(|_trigger: Trigger<Foob>| ());
        
    println!("Observed both triggers");

    entity.insert(Bar);

    println!("Didn't panic")
}

#[derive(Event)]
struct Foo;

#[derive(Event)]
struct Foob;

#[derive(Component)]
struct Bar;

What went wrong

When running the testing code snippet provided above, the test panics when calling entity.insert(Bar); thanks to the two lines calling `entity.observe(|_trigger: Trigger| {});. (See the screenshot below)

Additional information

To fix the test, any of the calls on entity can be commented out to get the test to run successfully.
Alternatively, you can move entity.insert(Bar); to earlier in the test which also avoids a panic.

To apply the workaround broadly, make sure that any .observe calls are made only after the entity has had all of it's components completely inserted.

Run of the failing test
Image

stdout
Finished `test` profile [optimized + debuginfo] target(s) in 2.21s
     Running unittests src/lib.rs (target/debug/deps/short_flight-cc6f80c42f537f0d)

running 1 test
test test::observe_underflow ... FAILED

failures:

---- test::observe_underflow stdout ----
Started test
Spawned empty entity
Observed both triggers

thread 'test::observe_underflow' panicked at /home/codespace/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.15.3/src/archetype.rs:587:38:
attempt to subtract with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test::observe_underflow

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

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

    Status

    Observer overhaul

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions