bevyengine/bevy · warning · AmbiguousSystemConflictsWarning

Systems with conflicting access have indeterminate run order

Error message

Systems with conflicting access have indeterminate run order: {:?}

What it means

Warning emitted when a schedule is built with ScheduleBuildSettings::ambiguity_detection enabled and two or more systems have conflicting World access (they cannot run in parallel) but no explicit relative order, so which one runs first is nondeterministic. It is a warning, not a hard error: the schedule still builds and runs. The payload (ConflictingSystems) lists each pair and the component ids they clash on (empty list means a general World conflict, e.g. an exclusive system).

Source

Thrown at crates/bevy_ecs/src/schedule/node.rs:710

                .map(|id| components.get_name(*id).unwrap())
                .collect();

            (name_a, name_b, conflict_names)
        })
    }
}

impl Deref for ConflictingSystems {
    type Target = Vec<(SystemKey, SystemKey, Box<[ComponentId]>)>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Error returned when there are ambiguous system conflicts detected.
#[derive(Error, Debug)]
#[error("Systems with conflicting access have indeterminate run order: {:?}", .0.0)]
pub struct AmbiguousSystemConflictsWarning(pub ConflictingSystems);

/// Container for system sets in a schedule.
#[derive(Default)]
pub struct SystemSets {
    /// List of system sets in the schedule.
    sets: SlotMap<SystemSetKey, InternedSystemSet>,
    /// List of conditions for each system set, in the same order as `sets`.
    conditions: SecondaryMap<SystemSetKey, Vec<ConditionWithAccess>>,
    /// Map from system sets to their keys.
    ids: HashMap<InternedSystemSet, SystemSetKey>,
    /// System sets that have not been initialized yet.
    uninit: Vec<UninitializedSet>,
}

/// A system set's conditions that have not been initialized yet.
struct UninitializedSet {
    key: SystemSetKey,

View on GitHub (pinned to 396ca72708)

Solutions

  1. Add an explicit order between the reported pair: .before()/.after(), put them in one .chain()ed tuple, or order their containing SystemSets.
  2. If the conflict is accidental, narrow one system's access (Changed<T>/Added<T> filters, disjoint components) so the accesses no longer conflict.
  3. If the order genuinely does not matter, leave ambiguity_detection off for that schedule (it is opt-in).

Example fix

// before
app.add_systems(Update, (advance_timers, apply_damage)); // both &mut Health, no order

// after
app.add_systems(Update, (advance_timers, apply_damage).chain());
Defensive patterns

Strategy: validation

Validate before calling

// Detect ambiguity during development only
app.add_schedule(Update, Schedule::new(Update).set_build_settings(ScheduleBuildSettings {
    ambiguity_detection: true,
    ..default()
}));

Prevention

When it happens

Trigger: Two systems with &mut access to the same component (or overlapping queries) added to the same schedule without .before/.after/.chain between them, while ambiguity detection is turned on for that schedule.

Common situations: Adding a new system that writes a component another system also writes; enabling ambiguity checks on a large existing app and getting a flood of pairs; cross-plugin systems that touch the same data with no shared set ordering.

Related errors


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