bevyengine / bevyengine/bevy

Adding an Observer that uses a trait query stops registering additional components for that trait

Open
#23,222 0 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Bug D-Complex S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version and features
version: 0.18.0
features: debug

## What you did

I've written a queryable trait ``T``
```
#[bevy_trait_query::queryable]
pub trait T {
fn foo(&self);
}
```
and some components implementing it, called ``A`` and ``B``
```
pub struct A;

impl T for A {
fn foo(&self) { }
}
```

```
pub struct B;

impl T for B {
fn foo(&self) { }
}
```

I've also got an observer making use of that query:
```
pub fn observer(
trigger: On,
trait_query: Query<&dyn Trait>,
)
```

lastly I register the components and added the observer in this order:
```
app.register_component_as::();
app.add_observer(observer);
app.register_component_as::();
```

## What went wrong

Instead of starting, the app panicked with the message: "Cannot register new trait impls after the game has started".

## Additional information
The panic occurred because the ``TraitImplRegistry<>`` for the trait ``T`` was sealed by the time component ``B`` was trying to register.
To the best of my knowledge, this is caused by the observer being spawned with a ``Query<&dyn T>`` parameter of the ``T`` trait, causing the ``TraitQueryState`` to be initialized. This initialization of the ``TraitQueryState`` seals the ``TraitImplRegistry``, which then leads to the above mentioned panic.

### Possible Workaround
PROMETHIA suggested delaying the creation of the observer to avoid this problem for now.

Below is one way to achieve this using the ``PreStartup`` schedule
```
app.add_systems(PreStartup, |world: &mut World| {
world.add_observer(observer);
});
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the registration order described in the issue, then inspect TraitQueryState and TraitImplRegistry initialization around observer creation. Confirm that adding an observer with Query<&dyn T> prevents the later registration of B; done means the reported order no longer panics while preserving trait-query behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.