bevyengine/bevy · error
Attempting to synchronize an entity that has already been sy
Error message
Attempting to synchronize an entity that has already been synchronized!
What it means
This panic fires in bevy_extract's entity_sync_system while processing an EntityRecord::Added: the main-world entity to be synchronized already carries a SubEntity<L> component, meaning a sub-world counterpart was already spawned for it. The SyncWorldPlugin records Add<SyncToSubWorld> observations in PendingSyncEntity; if the same entity gets an 'added' record while its SubEntity link still exists, the sync machinery treats it as a double-synchronization bug and aborts.
Source
Thrown at crates/bevy_extract/src/sync_world.rs:233
pub(crate) struct PendingSyncEntity<L: AppLabel + Clone + Copy + Eq> {
#[deref]
records: Vec<EntityRecord<L>>,
marker: PhantomData<L>,
}
pub(crate) fn entity_sync_system<L: AppLabel + Clone + Copy + Eq>(
main_world: &mut World,
sub_world: &mut World,
) {
main_world.resource_scope(|world, mut pending: Mut<PendingSyncEntity<L>>| {
// TODO : batching record
for record in pending.drain(..) {
match record {
EntityRecord::Added(e) => {
if let Ok(mut main_entity) = world.get_entity_mut(e) {
match main_entity.entry::<SubEntity<L>>() {
bevy_ecs::world::ComponentEntry::Occupied(_) => {
panic!("Attempting to synchronize an entity that has already been synchronized!");
}
bevy_ecs::world::ComponentEntry::Vacant(entry) => {
let id = sub_world.spawn(MainEntity(e)).id();
entry.insert(SubEntity::<L>(id, PhantomData));
}
};
}
}
EntityRecord::Removed(sub_entity) => {
if let Ok(ec) = sub_world.get_entity_mut(sub_entity.id()) {
ec.despawn();
};
}
EntityRecord::ComponentRemoved(main_entity, removal_function) => {
let Some(sub_entity) = world.get::<SubEntity<L>>(main_entity) else {
continue;
};View on GitHub (pinned to 396ca72708)
Solutions
- Ensure SyncWorldPlugin (and the label L) is registered exactly once per App; check app.get_schedule_plugins or your plugin adder for duplicates.
- Never remove SyncToSubWorld from a live entity — per its docs it should persist for the entity's entire lifecycle; despawn the entity instead.
- Don't manually insert SubEntity; let the sync system own that component.
- If restoring world state, clear PendingSyncEntity records and stale SubEntity components as part of the restore.
Example fix
// before eentity.remove::<SyncToSubWorld<SubApp>>(); // ... later re-add => double sync panic app.add_plugins(SyncWorldPlugin::<SubApp>::default()); app.add_plugins(SyncWorldPlugin::<SubApp>::default()); // duplicate // after // keep the marker for the entity's lifetime; despawn instead of removing: commands.entity(e).despawn(); // and register the plugin once: app.add_plugins(SyncWorldPlugin::<SubApp>::default());
Defensive patterns
Strategy: fallback
Prevention
- Keep SyncToSubWorld on an entity for its entire lifecycle; despawn to end synchronization instead of removing the marker.
- Register SyncWorldPlugin with a given AppLabel exactly once per App.
- Never insert SubEntity components manually; the sync system owns them.
- When snapshotting/restoring the main World, also clear PendingSyncEntity records and SubEntity links.
When it happens
Trigger: Removing and re-adding SyncToSubWorld (directly, or via removing/re-adding the ExtractComponentPlugin/SyncComponentPlugin machinery) on an entity whose SubEntity component was not cleaned up; running the sync system twice on the same PendingSyncEntity queue (double plugin registration with the same label L); manually inserting SubEntity onto entities; world state restored/duplicated while stale pending records remain.
Common situations: Adding SyncWorldPlugin::<SubApp>(default) twice or with the same AppLabel in multiple places; toggling extraction on an entity by removing/re-adding marker components each frame; snapshot/restore of the main World in editor hot-reload flows leaving both old SubEntity links and new Add records.
Related errors
- Cannot call `ReflectComponent::reflect_mut` on component {na
- Cannot call `ReflectComponent::reflect_unchecked_mut` on com
- component should represent a type.
- `{type_path}` should be registered in type registry via `App
- `{type_path}` should have #[reflect(Component)] or #[reflect
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/830ecb48bbf44666.
Report an issue: GitHub.