bevyengine/bevy · error · ScheduleBuildError
CrossDependency
CrossDependency
Error message
`{:?}` 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. What it means
`CrossDependency` means a node (system or set) has both an `in_set` relationship and a `before`/`after` relationship with the same set, possibly transitively. A system cannot be ordered strictly before or after a set it belongs to — every member ordering includes itself — so the constraint set is unsolvable and schedule initialization fails.
Source
Thrown at crates/bevy_ecs/src/schedule/error.rs:33
},
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)]
Elevated(#[from] ScheduleBuildWarning),
}
/// Category of warnings encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize).
#[non_exhaustive]
#[derive(Error, Debug)]View on GitHub (pinned to 396ca72708)
Solutions
- Order against a sibling instead of an enclosing set: point `.before`/`.after` at the specific system or a sibling set, not one that contains the constrained node
- If the member genuinely must bracket the set, split the set so the constrained member moves outside it
- Audit combined in_set + before/after configuration, including edges contributed by multiple plugins transitively
Example fix
// before app.add_systems(Update, cleanup.in_set(SimSet).after(SimSet)); // cross-dependency // after app.add_systems(Update, cleanup.after(sim_tick).after(sim_apply)); // order against members // or move cleanup out of SimSet
Defensive patterns
Strategy: try-catch
Validate before calling
// Before configuring, keep an explicit model of set membership and check:
// never order a node against a set that (transitively) contains it
fn contains(hierarchy: &SetHierarchy, set: SetId, maybe_descendant: SetId) -> bool { /* walk edges */ false } Try / catch
match schedule.initialize(&mut world) {
Err(ScheduleBuildError::CrossDependency(DagCrossDependencyError(a, b))) => {
// a is both inside and ordered against b: repoint the ordering at a sibling
}
other => other.map(|_| ()),
} Prevention
- Order within sets (member vs member), never member vs containing set
- When two plugins must interleave, order their sibling sets rather than nesting plus ordering
- Review every .before/.after against the in_set lattice after plugin merges
When it happens
Trigger: `.add_systems(s, my_system.in_set(MySet).before(MySet))`; or configuring `A.before(B)` where B contains A through a chain of `in_set` edges added by different plugins; run-conditions tuples that implicitly nest sets.
Common situations: Trying to pin one member of a set relative to the whole set ('run this cleanup after everything in Simulation'); plugin A ordering against plugin B's set while also adding its systems into that set; transitive containment making an apparently-legal ordering illegal.
Related errors
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/d7579c33a08b61c4.
Report an issue: GitHub.