bevyengine/bevy · critical

Error when initializing schedule

Error message

Error when initializing schedule {:?}: {}

What it means

Schedule::run initializes the schedule before executing it; if building the executable schedule fails (ordering cycles, self-loops, ambiguous SystemTypeSet ordering, other build errors), run() panics with this wrapper message. The text after the colon embeds the underlying ScheduleBuildError rendered against the graph and world, naming the offending nodes/edges. It fires on the first run of the schedule, typically the first frame.

Solutions

  1. Read the embedded detail after the colon - it identifies the exact nodes and constraint at fault; fix that underlying build error.
  2. Reproduce as a failing test: call app.update() once right after configuring systems so CI catches it before runtime.
  3. If you need the error instead of a panic, call schedule.initialize(&mut world) yourself and handle the Result before calling run().

Example fix

// before
schedule.run(&mut world); // panics on invalid graph

// after
if let Err(e) = schedule.initialize(&mut world) {
    log::error!("bad schedule: {}", e.to_string(schedule.graph(), world));
    return;
}
schedule.run(&mut world);
Defensive patterns

Strategy: try-catch

Validate before calling

// Fail fast in a test instead of frame 1
#[test]
fn app_boots() {
    let mut app = App::new();
    app.add_plugins(DefaultPlugins);
    app.update();
}

Try / catch

if let Err(e) = schedule.initialize(&mut world) {
    log::error!("schedule init failed: {}", e.to_string(schedule.graph(), world));
    return; // skip running instead of letting run() panic
}
schedule.run(&mut world);

Prevention

When it happens

Trigger: Any ScheduleBuildError surfacing through Schedule::run: a cycle or self-loop introduced by new ordering constraints, ordering against a duplicated system type, or graph inconsistencies added since the last successful run.

Common situations: App panics on frame 1 after adding a plugin or ordering constraint; systems/sets configured differently between test and app so a constraint only loops in one of them; large refactors of schedule configuration.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of bevyengine/bevy@a62cce8c05 (2026-08-20). Data as JSON: /api/errors/9e8ef7bae2ad9bd3. Report an issue: GitHub.

Appendix: source

Thrown at crates/bevy_ecs/src/schedule/schedule.rs:595

        self.executor_initialized = false;
        self
    }

    /// Set whether the schedule applies deferred system buffers on final time or not. This is a catch-all
    /// in case a system uses commands but was not explicitly ordered before an instance of
    /// [`ApplyDeferred`]. By default this
    /// setting is true, but may be disabled if needed.
    pub fn set_apply_final_deferred(&mut self, apply_final_deferred: bool) -> &mut Self {
        self.executor.set_apply_final_deferred(apply_final_deferred);
        self
    }

    /// Runs all systems in this schedule on the `world`, using its current execution strategy.
    pub fn run(&mut self, world: &mut World) {
        #[cfg(feature = "trace")]
        let _span = info_span!("schedule", name = ?self.label).entered();

        world.check_change_ticks();
        self.initialize(world).unwrap_or_else(|e| {
            panic!(
                "Error when initializing schedule {:?}: {}",
                self.label,
                e.to_string(self.graph(), world)
            )
        });

        let error_handler = world.fallback_error_handler();

        #[cfg(not(feature = "bevy_debug_stepping"))]
        self.executor
            .run(&mut self.executable, world, None, error_handler);

        #[cfg(feature = "bevy_debug_stepping")]
        {
            let skip_systems = match world.get_resource_mut::<Stepping>() {
                None => None,

View on GitHub (pinned to a62cce8c05)