bevyengine/bevy · error · ScheduleError
ScheduleNotFound
ScheduleNotFound
Error message
Schedule not found.
What it means
`ScheduleError::ScheduleNotFound` is returned by `Schedules::remove_systems_in_set` (and sibling `Schedules` methods) when `get_mut(schedule)` finds no schedule under that label — the schedule was never created via `add_systems`/`entry` for that `ScheduleLabel`. It is the schedules-collection level of 'key not present', distinct from `SetNotFound` which is set-level within an existing schedule.
Source
Thrown at crates/bevy_ecs/src/schedule/error.rs:292
}
ScheduleBuildWarning::Ambiguity(AmbiguousSystemConflictsWarning(ambiguities)) => {
ScheduleBuildError::ambiguity_to_string(ambiguities, graph, world.components())
}
}
}
}
/// Error returned from some `Schedule` methods
#[derive(Error, Debug)]
pub enum ScheduleError {
/// Operation cannot be completed because the schedule has changed and `Schedule::initialize` needs to be called
#[error("Operation cannot be completed because the schedule has changed and `Schedule::initialize` needs to be called")]
Uninitialized,
/// Method could not find set
#[error("Set not found")]
SetNotFound,
/// Schedule not found
#[error("Schedule not found.")]
ScheduleNotFound,
/// Error initializing schedule
#[error("{0}")]
ScheduleBuildError(ScheduleBuildError),
}
impl From<ScheduleBuildError> for ScheduleError {
fn from(value: ScheduleBuildError) -> Self {
Self::ScheduleBuildError(value)
}
}
View on GitHub (pinned to 396ca72708)
Solutions
- Create/populate the schedule first: `schedules.add_systems(Label, ...)` or use `.entry(Label)` which inserts on demand
- Double-check the exact label type and that the plugin owning the schedule was added before your call
- Handle the `Err` gracefully in optional-cleanup paths instead of unwrapping
Example fix
// before
let n = schedules.remove_systems_in_set(MyLabel, MySet, &mut world, policy)?; // ScheduleNotFound
// after
schedules.entry(MyLabel).add_systems(dummy_placeholder_free_marker); // ensure schedule exists
// or simply verify first:
if schedules.get_mut(MyLabel).is_some() { /* ... proceed ... */ } Defensive patterns
Strategy: try-catch
Validate before calling
// Check the schedule exists before operating on it
if schedules.get_mut(MyLabel).is_some() {
schedules.remove_systems_in_set(MyLabel, MySet, &mut world, policy)?;
}
// or create on demand: schedules.entry(MyLabel); Try / catch
match schedules.remove_systems_in_set(MyLabel, MySet, &mut world, policy) {
Err(ScheduleError::ScheduleNotFound) => Ok(0), // nothing to clean
other => other,
} Prevention
- Use .entry(label) when you want create-if-missing semantics on the Schedules collection
- Confirm label types (custom labels vs built-ins like Update) before removal calls
- Order plugin builds so schedule-creating plugins run before schedule-consuming cleanup
When it happens
Trigger: Calling `schedules.remove_systems_in_set(MyLabel, set, ...)` when no schedule exists under `MyLabel`; using a different (or custom) label type than the one the systems were added under; removing before the plugin that creates the schedule has built it.
Common situations: Two `ScheduleLabel` types with similar names (e.g. a custom `Update`-like label vs `Update`); plugin ordering where removal runs before creation; cleanup code in tests assuming a schedule exists.
Related errors
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/4ce2ab409ab2614d.
Report an issue: GitHub.