bevyengine/bevy · error · ScheduleNotInitialized
executable schedule has not been built
Error message
executable schedule has not been built
What it means
Returned (as an Err, not a panic) by Schedule::systems() and Schedule::systems_with_access() when the executable schedule has not been built yet - Schedule::initialize or Schedule::run has never been called for this schedule. These accessors read the built executable, so they require one initialization pass first.
Source
Thrown at crates/bevy_ecs/src/schedule/schedule.rs:1934
}
/// An event triggered when a schedule is successfully built.
///
/// Note: When this event is triggered, the corresponding [`Schedule`] is not present in the world.
/// So, observers will need to cache whatever data they need from this and access it later once the
/// schedule is not running.
#[derive(Event)]
pub struct ScheduleBuilt {
/// The schedule that was built.
pub label: InternedScheduleLabel,
/// The metadata for the build process of this schedule.
pub build_metadata: ScheduleBuildMetadata,
}
/// Error to denote that [`Schedule::initialize`] or [`Schedule::run`] has not yet been called for
/// this schedule.
#[derive(Error, Debug)]
#[error("executable schedule has not been built")]
pub struct ScheduleNotInitialized;
#[cfg(test)]
mod tests {
use alloc::{vec, vec::Vec};
use core::any::TypeId;
use bevy_ecs_macros::ScheduleLabel;
use crate::{
error::{ignore, panic, FallbackErrorHandler, Result},
prelude::{ApplyDeferred, IntoSystemSet, Res, Resource},
schedule::{
passes::AutoInsertApplyDeferredPass, tests::ResMut, FlattenedDependencies,
IntoScheduleConfigs, MultiThreadedExecutor, Schedule, ScheduleBuildPass,
ScheduleBuildSettings, ScheduleCleanupPolicy, SystemSet,
},
system::Commands,View on GitHub (pinned to 396ca72708)
Solutions
- Call schedule.initialize(&mut world) (or one schedule.run(&mut world)) before iterating systems.
- Defer inspection until after the first frame - e.g. react to the ScheduleBuilt event that fires when the schedule is built.
- Propagate the Result instead of unwrapping so callers can retry later.
Example fix
// before
for (key, system) in schedule.systems().unwrap() { /* Err(ScheduleNotInitialized) */ }
// after
schedule.initialize(&mut world)?;
for (key, system) in schedule.systems()? { /* ... */ } Defensive patterns
Strategy: retry
Validate before calling
// Ensure the executable exists before reading system info schedule.initialize(&mut world)?; let systems = schedule.systems()?; // Ok now
Try / catch
match schedule.systems() {
Ok(systems) => { /* iterate */ }
Err(ScheduleNotInitialized) => {
let _ = schedule.initialize(&mut world);
// retry next frame / after initialization
}
} Prevention
- Treat initialize() as a precondition of every schedule inspection API.
- Drive inspectors from the ScheduleBuilt event rather than polling before first run.
- In tests, run one update before asserting on schedule contents.
When it happens
Trigger: Calling schedule.systems() on a freshly constructed or freshly modified Schedule before initialize()/run(); inspector or stepping tooling enumerating systems of a schedule that has never executed.
Common situations: Editor/debug UIs listing systems at startup before the first frame; tests inspecting a newly assembled schedule without running it; code that assumes systems are enumerable immediately after add_systems.
Related errors
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/6d1d897320ce1682.
Report an issue: GitHub.