bevyengine/bevy · error · syn::Error

#[{meta}] only supports structs, not enums

Error message

#[{meta}] only supports structs, not enums

What it means

bevy_macro_utils::shape::get_struct_fields emits this compile error when a Bevy derive macro that only understands structs is applied to an enum. The error span points at the `enum` keyword of the offending type. It is generated by derives such as #[derive(Bundle)], #[derive(SystemParam)], #[derive(QueryData)] and #[derive(WorldQuery)], each passing its own name in `meta`.

Source

Thrown at crates/bevy_macro_utils/src/shape.rs:13

use syn::{
    punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataEnum, DataUnion, Error,
    Field, Fields,
};

/// Get the fields of a data structure if that structure is a struct;
/// otherwise, return a compile error that points to the site of the macro invocation.
///
/// `meta` should be the name of the macro calling this function.
pub fn get_struct_fields<'a>(data: &'a Data, meta: &str) -> Result<&'a Fields, Error> {
    match data {
        Data::Struct(data_struct) => Ok(&data_struct.fields),
        Data::Enum(DataEnum { enum_token, .. }) => Err(Error::new(
            enum_token.span(),
            format!("#[{meta}] only supports structs, not enums"),
        )),
        Data::Union(DataUnion { union_token, .. }) => Err(Error::new(
            union_token.span(),
            format!("#[{meta}] only supports structs, not unions"),
        )),
    }
}

/// Return an error if `Fields` is not `Fields::Named`
pub fn require_named<'a>(fields: &'a Fields) -> Result<&'a Punctuated<Field, Comma>, Error> {
    if let Fields::Named(fields) = fields {
        Ok(&fields.named)
    } else {
        Err(Error::new(
            fields.span(),
            "Unnamed fields are not supported here",

View on GitHub (pinned to 396ca72708)

Solutions

  1. Convert the enum into a struct (named- or tuple-fields) whose fields are the components/params you intended to group.
  2. For Bundle specifically, model alternatives at runtime: add a discriminant Component/enum state field and optional components instead of an enum Bundle.
  3. For SystemParam alternatives, split into multiple systems or use Option<P> params rather than an enum param.

Example fix

// before
#[derive(Bundle)]
enum MovementBundle {
    Run { walk: Walk, sprint: Sprint },
    Idle { idle: Idle },
}

// after
#[derive(Bundle)]
struct MovementBundle {
    movement: Movement, // enum component carries the variant
    walk: Option<Walk>,
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Writing `#[derive(Bundle)] enum MyBundle { ... }`, or an enum with #[derive(SystemParam)], #[derive(QueryData)], or the render Specializer derive. The macro calls get_struct_fields(&ast.data, meta), matches Data::Enum, and returns the syn::Error.

Common situations: Trying to model 'one of several component groups' as a Bundle enum; migrating a struct to an enum while leaving the derive attached; assuming Bundle behaves like Rust's enum-based state machines.

Related errors


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