Archetype bug panics when calling EntityWorldMut::observe several times before calling EntityWorldMut::insert
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## 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
```rust
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| ());
entity.observe(|_trigger: Trigger| ());
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

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`
```
Contributor guide
Research direction
Start by reproducing the test with EntityWorldMut::observe called twice before EntityWorldMut::insert, then trace the panic reported at bevy_ecs-0.15.3/src/archetype.rs:587:38. Inspect the EntityWorldMut observe and insert paths and add a regression test for this sequence. Done means the reproduction no longer panics and the test passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100