From 9052d0bda33eeb5db831b09fa86faac8f4e98d9f Mon Sep 17 00:00:00 2001 From: rewin Date: Mon, 13 Jul 2026 21:30:38 +0800 Subject: [PATCH 1/2] Add warn_once to wgpu backend once case and add regression test --- crates/bevy_render/src/sync_component.rs | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/sync_component.rs b/crates/bevy_render/src/sync_component.rs index 5ec00b2ffc896..64e9b9eda86cf 100644 --- a/crates/bevy_render/src/sync_component.rs +++ b/crates/bevy_render/src/sync_component.rs @@ -11,6 +11,8 @@ use crate::{ RenderApp, }; +use bevy_log::warn_once; + /// Plugin that registers a component for automatic sync to the render world. See [`SyncWorldPlugin`] for more information. /// /// This plugin is automatically added by [`ExtractComponentPlugin`], and only needs to be added for manual extraction implementations. @@ -57,7 +59,10 @@ impl, F: Send + Sync + 'static> Plugin app.world_mut() .register_component_hooks::() .on_remove(|mut world, context| { - let mut pending = world.resource_mut::(); + let Some(mut pending) = world.get_resource_mut::() else { + warn_once!("A component with render sync plugin was removed, but the render world does not exist (probably `WgpuSettings {{ backends: None }}`), so there is nothing to sync. Skip sync to render world."); + return; + }; pending.push(EntityRecord::ComponentRemoved( context.entity, |mut entity| { @@ -67,3 +72,32 @@ impl, F: Send + Sync + 'static> Plugin }); } } + + +#[cfg(test)] +mod tests { + use bevy_app::App; + use bevy_ecs::component::Component; + + use super::{SyncComponent, SyncComponentPlugin}; + use crate::RenderApp; + + #[derive(Component)] + struct TestSyncComponent; + + impl SyncComponent for TestSyncComponent { + type Target = Self; + } + + // Regression test for https://github.com/bevyengine/bevy/issues/24927: + // with `WgpuSettings { backends: None }` there is no render world, and Bevy used to crash on removing any synced component. + // This test checks that the bug does not happen again. + #[test] + fn remove_synced_component_without_render_world() { + let mut app = App::new(); + app.add_plugins(SyncComponentPlugin::::default()); + + let entity = app.world_mut().spawn(TestSyncComponent).id(); + app.world_mut().despawn(entity); + } +} \ No newline at end of file From aa3b7dc4aaf4c1fb9e2da8050e0e86fd41954e8b Mon Sep 17 00:00:00 2001 From: rewin Date: Mon, 13 Jul 2026 21:46:50 +0800 Subject: [PATCH 2/2] fmt fix --- crates/bevy_render/src/sync_component.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_render/src/sync_component.rs b/crates/bevy_render/src/sync_component.rs index 64e9b9eda86cf..3a955f32d7c81 100644 --- a/crates/bevy_render/src/sync_component.rs +++ b/crates/bevy_render/src/sync_component.rs @@ -73,7 +73,6 @@ impl, F: Send + Sync + 'static> Plugin } } - #[cfg(test)] mod tests { use bevy_app::App; @@ -100,4 +99,4 @@ mod tests { let entity = app.world_mut().spawn(TestSyncComponent).id(); app.world_mut().despawn(entity); } -} \ No newline at end of file +}