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
- Convert the enum into a struct (named- or tuple-fields) whose fields are the components/params you intended to group.
- For Bundle specifically, model alternatives at runtime: add a discriminant Component/enum state field and optional components instead of an enum Bundle.
- 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
- Only attach struct-only derives (Bundle, SystemParam, QueryData, WorldQuery, Specializer) to `struct` items.
- Model mutually-exclusive component sets as an enum Component field plus optional components, not an enum Bundle.
- Let the derive's error message guide you: it points at the `enum` keyword of the offending type.
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
- Union types are not supported yet.
- Expected a Template type path
- Can only derive VariantDefaults for enums
- #[{meta}] only supports structs, not unions
- Unnamed fields are not supported here
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/37e3739ee884aa17.
Report an issue: GitHub.