bevyengine/bevy · critical

DrawFunctions<{}> must be added to the world as a resource b

Error message

DrawFunctions<{}> must be added to the world as a resource before adding render commands to it

What it means

SubApp::add_render_command (draw.rs:372) panics when the DrawFunctions<P> resource has not been added to that world yet. Render commands for phase item type P are stored inside the DrawFunctions<P> resource, so the resource must be initialized before any command is added. The panic names P so you know which phase's resource is missing.

Source

Thrown at crates/bevy_render/src/render_phase/draw.rs:372

        &mut self,
    ) -> &mut Self
    where
        C::Param: ReadOnlySystemParam;
}

impl AddRenderCommand for SubApp {
    fn add_render_command<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static>(
        &mut self,
    ) -> &mut Self
    where
        C::Param: ReadOnlySystemParam,
    {
        let draw_function = RenderCommandState::<P, C>::new(self.world_mut());
        let draw_functions = self
            .world()
            .get_resource::<DrawFunctions<P>>()
            .unwrap_or_else(|| {
                panic!(
                    "DrawFunctions<{}> must be added to the world as a resource \
                     before adding render commands to it",
                    core::any::type_name::<P>(),
                );
            });
        draw_functions.write().add_with::<C, _>(draw_function);
        self
    }
}

impl AddRenderCommand for App {
    fn add_render_command<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static>(
        &mut self,
    ) -> &mut Self
    where
        C::Param: ReadOnlySystemParam,
    {
        SubApp::add_render_command::<P, C>(self.main_mut());

View on GitHub (pinned to 396ca72708)

Solutions

  1. Init the resource first: render_app.init_resource::<DrawFunctions<P>>() in your plugin build, then call add_render_command.
  2. Make sure you are operating on the render sub-app (app.get_sub_app_mut(RenderApp) / RenderApp), not the main world.
  3. For built-in phases, ensure the corresponding core plugin (which inits DrawFunctions) is added before your plugin (add a plugin dependency).

Example fix

// before: added on the main app world, resource not present
app.add_render_command::<Opaque3d, DrawCustom>();

// after: go through the render sub-app and init the resource for custom phases
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
    render_app
        .init_resource::<DrawFunctions<CustomPhaseItem>>() // for custom phases
        .add_render_command::<CustomPhaseItem, DrawCustom>();
}
Defensive patterns

Strategy: validation

Validate before calling

if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
    if !render_app.world().contains_resource::<DrawFunctions<CustomPhaseItem>>() {
        render_app.init_resource::<DrawFunctions<CustomPhaseItem>>();
    }
    render_app.add_render_command::<CustomPhaseItem, DrawCustom>();
}

Prevention

When it happens

Trigger: Calling add_render_command on an app/world where init_resource::<DrawFunctions<P>>() has not run - most commonly calling it on the main app world instead of the Render sub-app, or a custom phase plugin that forgets to init the resource before registering commands.

Common situations: Custom render phases: forgetting render_app.init_resource::<DrawFunctions<MyPhaseItem>>() in the plugin; adding render commands in Plugin::build without going through app.get_sub_app_mut(RenderApp); using a built-in phase (e.g. Opaque3d) before the plugin that initializes its DrawFunctions is added; Bevy version migrations that moved where the resource is initialized.

Related errors


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