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

  1. Call schedule.initialize(&mut world) (or one schedule.run(&mut world)) before iterating systems.
  2. Defer inspection until after the first frame - e.g. react to the ScheduleBuilt event that fires when the schedule is built.
  3. 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

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.