bevyengine/bevy · error · DagOverlappingGroupError

DAG has overlapping groups between keys {0:?} and {1:?}

Error message

DAG has overlapping groups between keys {0:?} and {1:?}

What it means

`DagOverlappingGroupError` is the low-level graph error reporting that groups keyed `{0}` and `{1}` have overlapping members while also carrying an ordering between the group keys. Bevy wraps it as `ScheduleBuildError::SetsHaveOrderButIntersect`: two ordered system sets share at least one system, so that system has no consistent position.

Source

Thrown at crates/bevy_ecs/src/schedule/graph/dag.rs:724

impl<K: Debug, V: Debug, S> Debug for DagGroups<K, V, S> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("DagGroups").field(&self.0).finish()
    }
}

/// Error indicating that the graph has redundant edges.
#[derive(Error, Debug)]
#[error("DAG has redundant edges: {0:?}")]
pub struct DagRedundancyError<N: GraphNodeId>(pub Vec<(N, N)>);

/// Error indicating that two graphs both have a dependency between the same nodes.
#[derive(Error, Debug)]
#[error("DAG has a cross-dependency between nodes {0:?} and {1:?}")]
pub struct DagCrossDependencyError<N>(pub N, pub N);

/// Error indicating that the graph has overlapping groups between two keys.
#[derive(Error, Debug)]
#[error("DAG has overlapping groups between keys {0:?} and {1:?}")]
pub struct DagOverlappingGroupError<K>(pub K, pub K);

#[cfg(test)]
mod tests {
    use core::ops::DerefMut;

    use crate::schedule::graph::{index, Dag, Direction, GraphNodeId, UnGraph};

    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    struct TestNode(u32);

    impl GraphNodeId for TestNode {
        type Adjacent = (TestNode, Direction);
        type Edge = (TestNode, TestNode);

        fn kind(&self) -> &'static str {
            "test node"
        }

View on GitHub (pinned to 396ca72708)

Solutions

  1. Give each system a single membership among the two ordered sets
  2. Remove the ordering between the intersecting sets, ordering specific non-shared systems instead
  3. Factor shared systems into a third set that both original sets relate to without intersection

Example fix

// before
app.configure_sets(Update, A.before(B));
app.add_systems(Update, shared.in_set(A).in_set(B)); // DagOverlappingGroupError(A, B)

// after
app.configure_sets(Update, A.before(B));
app.add_systems(Update, shared.in_set(A));
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard at config time: ordered sets must be disjoint
fn safe_to_order(a: &SetMembers, b: &SetMembers) -> bool {
    a.intersection(b).next().is_none()
}

Try / catch

match schedule.initialize(&mut world) {
    Err(ScheduleBuildError::SetsHaveOrderButIntersect(err @ DagOverlappingGroupError(_, _))) => {
        // err.0/err.1 name the two set keys; remove the shared membership or the ordering
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: The same condition as `SetsHaveOrderButIntersect` — sets A and B with `A.before(B)` (possibly transitively) and at least one system registered in both. Encountered raw when matching the inner error or using the Dag grouping API directly.

Common situations: Cross-cutting sets (debug/networking) collecting systems that also live in ordered phase sets; plugin composition layering multiple memberships per system; refactors adding a second `.in_set` without checking the sets are unordered relative to each other.

Related errors


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