Open-Source Wikis

/

Bevy

/

How to contribute

/

Debugging

bevyengine/bevy

Debugging

How to find what's wrong, both when developing Bevy itself and when shipping a game on top of it.

The official docs at docs/debugging.md and docs/profiling.md cover the basics. This page is the practical companion.

Logs

Bevy uses tracing for both events and spans. The integration is in bevy_log. Filtering follows the standard RUST_LOG syntax:

# Everything at info, but bevy_render at debug
RUST_LOG=info,bevy_render=debug cargo run --example 3d_scene

# Trace level for a specific crate
RUST_LOG=bevy_ecs=trace cargo run

# Multiple filters
RUST_LOG=warn,bevy_app=info,bevy_asset=debug cargo run

bevy_log registers a tracing-subscriber formatter at startup; LogPlugin::default() honors RUST_LOG, or you can override the filter directly:

App::new().add_plugins(DefaultPlugins.set(LogPlugin {
    filter: "bevy_render=debug,wgpu=warn".into(),
    level: bevy::log::Level::INFO,
    ..default()
}));

Tracing spans and Tracy

Bevy instruments hot paths with tracing spans. Enable the trace cargo feature to record them at runtime:

cargo run --features trace,trace_tracy --example many_cubes

trace_tracy integrates with Tracy via tracy-client. Running Tracy's UI alongside the example gives a per-frame waterfall.

Other tracing backends are available behind cargo features in crates/bevy_log/Cargo.toml:

  • trace_chrome — emits a Chrome chrome://tracing JSON file.
  • tracing-tracy — Tracy backend.
  • trace_tracy_memory — memory allocation hooks.

Profilers

docs/profiling.md walks through:

  • CPU profilingcargo flamegraph, samply, cargo-instruments on macOS.
  • GPU profiling — RenderDoc, Xcode's GPU debugger, RGP for AMD, Nsight for NVIDIA.

For Bevy-specific GPU work, the render graph nodes are individually labeled (search crates/bevy_core_pipeline/src/ for RenderLabel enums) and show up by name in any GPU debugger that supports labeled passes.

Built-in dev tools

The bevy_dev_tools crate provides:

  • FpsOverlayPlugin — on-screen FPS counter.
  • StateInspectorPlugin (when dev features are on) — visual inspector for States.
  • fps_overlay example — minimal demo.

The diagnostics framework in bevy_diagnostic lets you add custom counters that show up in the same overlay or in LogDiagnosticsPlugin's console output.

The Bevy Remote Protocol (BRP)

The most powerful debugging surface is the BRP. Enable the bevy_remote cargo feature, add RemotePlugin and RemoteHttpPlugin, and a JSON-RPC interface comes online on http://127.0.0.1:15702.

You can then query the world from anywhere:

curl -X POST http://127.0.0.1:15702 \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"bevy/list"}'

This is the foundation of the upcoming inspector; it's also the easiest way to debug a running game without rebuilding.

Common errors and how to diagnose them

"the trait bound T: Component is not satisfied"

Forgot #[derive(Component)]. Re-derive on the type and ensure it's Send + Sync + 'static.

"Resource X does not exist"

A system used Res<X> but no plugin inserted X. Either add app.insert_resource(X::default()) or guard the system with if_resource_exists::<X> / Option<Res<X>>.

"Query parameters are mutually conflicting"

Two parameters of the same system want the same component with conflicting access (e.g., two Query<&mut T> on the same archetype). Either use one query with Or<...> filters, or split into separate systems. The compiler error usually pinpoints the conflict.

"Schedule X is not registered"

Most often: forgot to call app.init_schedule(MyLabel) or used a label whose schedule was added in a SubApp other than the main one.

Renders to a blank window

Almost always either (a) no camera spawned, (b) camera and entity not on the same RenderLayers, (c) entity culled by Visibility/ViewVisibility, or (d) a missing MeshMaterial3d/MeshMaterial2d component.

"wgpu validation error" on startup

GPU adapter doesn't support the requested features. Set the WGPU_BACKEND env var (e.g. WGPU_BACKEND=vulkan) or look at the printed adapter info to see which limit was exceeded.

Catching panics

bevy_app::PanicHandlerPlugin (in DefaultPlugins) installs a panic hook that prints a stack trace via tracing::error!. On Wasm, panics surface in the browser console. The panic handler is in crates/bevy_app/src/panic_handler.rs.

For production builds, set the BEVY_BACKTRACE=full env var to get unwound stack traces with symbols.

Inspecting schedules

The schedule graph is queryable at runtime:

fn dump_schedule(schedules: Res<Schedules>) {
    for (label, schedule) in schedules.iter() {
        println!("{:?}: {} systems", label, schedule.systems().count());
    }
}

For a richer view, use bevy-inspector-egui (third-party). The BRP also exposes schedule introspection for tooling.

When all else fails

  • Check target/debug/build/<crate>-<hash>/output for build-script logs.
  • Run cargo clean -p <crate> if you suspect stale artifacts.
  • Try the bevy_dev_tools picking_debug example to confirm picking events route correctly.
  • Ask in #dev-help on the Bevy Discord with a minimal reproduction.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Debugging – Bevy wiki | Factory