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

  1. Ensure SyncWorldPlugin (and the label L) is registered exactly once per App; check app.get_schedule_plugins or your plugin adder for duplicates.
  2. Never remove SyncToSubWorld from a live entity — per its docs it should persist for the entity's entire lifecycle; despawn the entity instead.
  3. Don't manually insert SubEntity; let the sync system own that component.
  4. 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

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


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/830ecb48bbf44666. Report an issue: GitHub.