bevyengine/bevy · error

bevy_ecs should be found in manifest

Error message

bevy_ecs should be found in manifest

What it means

This expect() panic happens at COMPILE TIME inside the #[derive(ExtractComponent)] macro from bevy_extract. The macro resolves the path to bevy_ecs by scanning the crate manifest (BevyManifest); if 'bevy_ecs' cannot be found as a dependency in the invoking crate's Cargo.toml, maybe_get_path returns None and the derive aborts with 'bevy_ecs should be found in manifest'. It is a build-script/proc-macro environment problem, not a runtime error.

Source

Thrown at crates/bevy_extract/macros/src/extract_component.rs:12

use bevy_macro_utils::fq_std::{FQClone, FQOption};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, punctuated::Punctuated, DeriveInput, Path};

pub fn derive_extract_component(input: TokenStream) -> TokenStream {
    let mut ast = parse_macro_input!(input as DeriveInput);
    let bevy_extract_path: Path = crate::bevy_extract_path();
    let bevy_ecs_path: Path = bevy_macro_utils::BevyManifest::shared(|manifest| {
        manifest
            .maybe_get_path("bevy_ecs")
            .expect("bevy_ecs should be found in manifest")
    });

    ast.generics
        .make_where_clause()
        .predicates
        .push(parse_quote! { Self: #FQClone });

    let struct_name = &ast.ident;
    let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();

    let Some(attr) = ast.attrs.iter().find(|a| a.path().is_ident("extract_app")) else {
        return syn::Error::new_spanned(
            &ast.ident,
            "ExtractComponent requires #[extract_app(MyAppLabelA, MyAppLabelB)] to specify the target sub-app(s)",
        )
        .to_compile_error()
        .into();
    };

View on GitHub (pinned to 396ca72708)

Solutions

  1. Add bevy_ecs to the invoking crate's Cargo.toml: bevy_ecs = "<matching version>" (or via the bevy umbrella crate at the same version).
  2. Keep dependency versions in lockstep with bevy_extract/bevy_render to avoid mixed-version manifest lookups.
  3. If you don't need ECS types in that derive, check whether a re-export path (bevy::ecs) is available and depend on the umbrella bevy crate instead.
  4. Verify the derive is actually the one you intend (bevy_extract's) and that no custom BevyManifest path env overrides break resolution.

Example fix

# before (Cargo.toml of the deriving crate)
[dependencies]
bevy_extract = "0.19"
# derive fails: bevy_ecs should be found in manifest

# after
[dependencies]
bevy_ecs = "0.19"
bevy_extract = "0.19"
Defensive patterns

Strategy: validation

Validate before calling

# In Cargo.toml of the crate using #[derive(ExtractComponent)]:
[dependencies]
bevy_ecs = "0.19"   # must match the bevy_extract/bevy version in use
bevy_extract = "0.19"

Prevention

When it happens

Trigger: Using #[derive(ExtractComponent)] in a crate whose Cargo.toml does not list bevy_ecs as a dependency; depending on bevy_extract (or bevy_render re-exports) without also pulling bevy_ecs; workspace setups where the dependency is renamed or only present as a transitive dep.

Common situations: Splitting a Bevy project into workspace crates and forgetting bevy_ecs in the crate that derives ExtractComponent; using the new bevy_extract crate directly in external code; renaming dependencies in Cargo.toml so manifest path resolution fails.

Related errors


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