{"record":{"id":"33492c59f074630b","repo":"bevyengine/bevy","slug":"hierarchysort","errorCode":"HierarchySort","errorMessage":"Failed to topologically sort the hierarchy of system sets: {0}","messagePattern":"Failed to topologically sort the hierarchy of system sets: (.+?)","errorType":"error_code","errorClass":"ScheduleBuildError","httpStatus":null,"severity":"error","filePath":"crates/bevy_ecs/src/schedule/error.rs","lineNumber":24,"sourceCode":"use crate::{\n    component::Components,\n    schedule::{\n        graph::{\n            DagCrossDependencyError, DagOverlappingGroupError, DagRedundancyError,\n            DiGraphToposortError, GraphNodeId,\n        },\n        AmbiguousSystemConflictsWarning, ConflictingSystems, NodeId, ScheduleGraph, SystemKey,\n        SystemSetKey, SystemTypeSetAmbiguityError,\n    },\n    world::World,\n};\n\n/// Category of errors encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize).\n#[non_exhaustive]\n#[derive(Error, Debug)]\npub enum ScheduleBuildError {\n    /// Tried to topologically sort the hierarchy of system sets.\n    #[error(\"Failed to topologically sort the hierarchy of system sets: {0}\")]\n    HierarchySort(DiGraphToposortError<NodeId>),\n    /// Tried to topologically sort the dependency graph.\n    #[error(\"Failed to topologically sort the dependency graph: {0}\")]\n    DependencySort(DiGraphToposortError<NodeId>),\n    /// Tried to topologically sort the flattened dependency graph.\n    #[error(\"Failed to topologically sort the flattened dependency graph: {0}\")]\n    FlatDependencySort(DiGraphToposortError<SystemKey>),\n    /// Tried to order a system (set) relative to a system set it belongs to.\n    #[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)]\n    CrossDependency(#[from] DagCrossDependencyError<NodeId>),\n    /// Tried to order system sets that share systems.\n    #[error(\"`{:?}` and `{:?}` have a `before`-`after` relationship (which may be transitive) but share systems.\", .0.0, .0.1)]\n    SetsHaveOrderButIntersect(#[from] DagOverlappingGroupError<SystemSetKey>),\n    /// Tried to order a system (set) relative to all instances of some system function.\n    #[error(transparent)]\n    SystemTypeSetAmbiguity(#[from] SystemTypeSetAmbiguityError),\n    /// Tried to run a schedule before all of its systems have been initialized.\n    #[error(\"Tried to run a schedule before all of its systems have been initialized.\")]","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_ecs/src/schedule/error.rs#L6-L42","documentation":"During `Schedule::initialize`, Bevy topologically sorts the system-set hierarchy (the `in_set` containment graph). `HierarchySort` reports that this graph has a cycle: set containment is circular (directly or through a chain), so no valid nesting order exists. The wrapped `DiGraphToposortError<NodeId>` names the node where the cycle was detected.","triggerScenarios":"`.configure_sets(Schedule, A.in_set(B))` combined (directly or transitively) with `B.in_set(A)`; a set configured into itself (`A.in_set(A)`); two plugins that each nest their set inside the other's.","commonSituations":"Merging plugins that mutually reference each other's sets; refactoring set hierarchies and leaving an old `.in_set` edge behind; copy-pasted configure_sets calls that reverse the intended nesting.","solutions":["Read the node ids in the error and map them back to sets (the error's formatting includes the failing node), then delete one `.in_set` edge to break the loop","Check for mutual nesting introduced by two different plugins each configuring the other's set","Reproduce the schedule in a small test and remove edges until it initializes to confirm the cycle is gone"],"exampleFix":"// before\napp.configure_sets(Update, (SetA.in_set(SetB), SetB.in_set(SetA))); // cycle\n\n// after\napp.configure_sets(Update, (SetA.in_set(SetB),));","handlingStrategy":"try-catch","validationCode":"// Validate set-hierarchy acyclicity cheaply before adding a nesting edge\n// (maintain your own adjacency for plugin-owned sets, or rely on initialize below)\nlet result = schedule.initialize(&mut world);\nmatch result {\n    Ok(_) => {}\n    Err(e) => tracing::error!(%e, \"schedule build failed\"),\n}","typeGuard":null,"tryCatchPattern":"match schedule.initialize(&mut world) {\n    Ok(_) => { /* proceed */ }\n    Err(ScheduleBuildError::HierarchySort(err)) => {\n        // err carries the NodeId where the cycle was detected; fix the .in_set edges\n    }\n    Err(other) => return Err(other.into()),\n}","preventionTips":["Declare each set's parent in exactly one place (its owning plugin)","Keep a documented diagram of the set hierarchy as it grows","Initialize schedules in a dedicated test per plugin configuration to catch cycles at CI time"],"tags":["bevy","ecs","schedule","system-sets","cycle","topological-sort"],"backgroundTag":"dependency-cycle","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}