bevyengine/bevy · error · ScheduleBuildError

DependencySort

DependencySort

Error message

Failed to topologically sort the dependency graph: {0}

What it means

The dependency graph holds the `before`/`after` ordering constraints between systems and sets. `DependencySort` means that graph has a cycle: the ordering constraints form a loop, so no execution order satisfies them. This surfaces from `Schedule::initialize`, typically on the first run of the schedule.

Source

Thrown at crates/bevy_ecs/src/schedule/error.rs:27

        graph::{
            DagCrossDependencyError, DagOverlappingGroupError, DagRedundancyError,
            DiGraphToposortError, GraphNodeId,
        },
        AmbiguousSystemConflictsWarning, ConflictingSystems, NodeId, ScheduleGraph, SystemKey,
        SystemSetKey, SystemTypeSetAmbiguityError,
    },
    world::World,
};

/// Category of errors encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize).
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum ScheduleBuildError {
    /// Tried to topologically sort the hierarchy of system sets.
    #[error("Failed to topologically sort the hierarchy of system sets: {0}")]
    HierarchySort(DiGraphToposortError<NodeId>),
    /// Tried to topologically sort the dependency graph.
    #[error("Failed to topologically sort the dependency graph: {0}")]
    DependencySort(DiGraphToposortError<NodeId>),
    /// Tried to topologically sort the flattened dependency graph.
    #[error("Failed to topologically sort the flattened dependency graph: {0}")]
    FlatDependencySort(DiGraphToposortError<SystemKey>),
    /// Tried to order a system (set) relative to a system set it belongs to.
    #[error("`{:?}` and `{:?}` have both `in_set` and `before`-`after` relationships (these might be transitive). This combination is unsolvable as a system cannot run before or after a set it belongs to.", .0.0, .0.1)]
    CrossDependency(#[from] DagCrossDependencyError<NodeId>),
    /// Tried to order system sets that share systems.
    #[error("`{:?}` and `{:?}` have a `before`-`after` relationship (which may be transitive) but share systems.", .0.0, .0.1)]
    SetsHaveOrderButIntersect(#[from] DagOverlappingGroupError<SystemSetKey>),
    /// Tried to order a system (set) relative to all instances of some system function.
    #[error(transparent)]
    SystemTypeSetAmbiguity(#[from] SystemTypeSetAmbiguityError),
    /// Tried to run a schedule before all of its systems have been initialized.
    #[error("Tried to run a schedule before all of its systems have been initialized.")]
    Uninitialized,
    /// A warning that was elevated to an error.
    #[error(transparent)]

View on GitHub (pinned to 396ca72708)

Solutions

  1. Remove one edge in the reported cycle — the error identifies the nodes where topological sort stalled; map them back to the systems/sets
  2. Audit plugin boundaries for symmetric before/after pairs and pick a single direction
  3. Prefer `.in_set` plus one owner of ordering per relationship instead of ad-hoc pairwise `.before`/`.after`

Example fix

// before
app.add_systems(Update, (a.before(b), b.before(a))); // cycle

// after
app.add_systems(Update, (a.before(b),));
Defensive patterns

Strategy: try-catch

Validate before calling

// Before adding symmetric ordering, check the inverse edge in your own config model
// or just attempt an early initialize in dev builds:
#[cfg(test)]
fn assert_builds(schedule: &mut Schedule, world: &mut World) {
    schedule.initialize(world).expect("schedule must build");
}

Try / catch

match schedule.initialize(&mut world) {
    Err(ScheduleBuildError::DependencySort(err)) => {
        // err identifies the NodeId where ordering constraints cycled; remove one .before/.after edge
    }
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: `a.before(b)` together with `b.before(a)` (or a longer transitive chain a→b→c→a); symmetric `.before`/`.after` introduced when merging plugins that each order against the other's systems; a set ordered before one of its own members indirectly.

Common situations: Two plugins mutually ordering their systems for 'safety'; incremental addition of ordering constraints over time that accidentally closes a loop; conditional ordering macros that expand to more edges than expected.

Related errors


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