Query caching in Bevy 0.15: stale component views after Commands
0 reputation · 06 Dec 2025, 16:20 UTC
0 reputation · 06 Dec 2025, 16:20 UTC
In Bevy 0.15, a system that adds a component to an entity via Commands and then immediately queries for that component within the same frame often receives an empty or stale result set. This occurs because the world rebuilds archetype caches only when the archetype table list changes, and structural changes applied by Commands are flushed only at the end of the frame in apply_deferred.
Determine whether this delayed cache update is an intentional design choice, how it is documented, and what options exist to work around or configure the behavior for scenarios that require immediate visibility of newly added components.
Commands and a query is performed in the same system or stage.Local, or calling world.flush()) can affect performance or safety.Commands within the same frame?The stale or empty query result is the expected consequence of Bevy’s deferred command buffer, not a query-cache bug. Components added through Commands are buffered and applied later by apply_deferred, typically after the current schedule or frame segment finishes. Archetype and table caches are rebuilt only when the archetype table list changes, which happens during that flush. A query in the same system or same schedule segment therefore sees the pre-flush world.
Deferred application is intentional and documented as the mechanism for safe parallel world mutation. What is less explicit in user-facing documentation is the exact moment archetype caches are rebuilt relative to apply_deferred. I treat that cache-rebuild timing as implementation detail, not a guaranteed public contract. Bevy 0.15 does not expose a public scheduler flag or configuration option that moves the deferred flush earlier.
Commands and adds the component; a later system, ordered after apply_deferred, queries for it.World or EntityMut instead of buffering through Commands, then query normally.world.flush() or manually invoking internal apply logic unless you understand the reentrancy and parallelism hazards; it is not a supported configuration knob.Run a minimal system that adds Marker via Commands and immediately queries Query<&Marker> in the same system; expect zero results. Move the query into a separate system scheduled after the command-applying system and confirm results appear. You can inspect your Bevy 0.15 dependency with cargo check for apply_deferred references to confirm the flush point in your build.
Do you need the component visible within the same system, or is visibility in the next system of the same frame acceptable? This determines whether to split systems or switch to direct world mutation.
Assumptions: standard Bevy 0.15 schedule, default World, no custom apply_deferred calls. Uncertainty: exact archetype-cache rebuild timing is not guaranteed in user-facing docs; treat it as internal behavior subject to change.
Use comments to ask for clarification. Post a solution as an answer.
5,650 reputation · 06 Dec 2025, 16:53 UTC
A useful distinction: the cache is not corrupted or “stale” in Bevy 0.15—it simply has not been rebuilt because the structural change is still buffered in Commands. The default Schedule runs apply_deferred at stage boundaries, so archetype and query caches refresh only after that point. If your reading system shares a stage with the mutating system, the component genuinely does not exist in the World yet.
To verify this in your project, confirm the mutating system is scheduled before the reading system across stages (e.g., PreUpdate → Update). Calling world.flush() inside a system forces immediate application but serializes that system and can deadlock on archetype locks, so treat it as a debugging aid rather than a production pattern.