bevyengine/bevy · error

Union types are not supported yet.

Error message

Union types are not supported yet.

What it means

The FromTemplate proc macro in bevy_ecs synthesizes a companion `{Type}Template` struct plus `Template` and `Default` impls for the annotated type. It only has code paths for `Data::Struct` and `Data::Enum`; the `Data::Union` arm at template.rs:305 unconditionally panics. Unions have overlapping-field memory layouts for which no template can be generated.

Source

Thrown at crates/bevy_ecs/macros/src/template.rs:305

                            #(#variant_builds,)*
                        })
                    }

                    fn clone_template(&self) -> Self {
                        match self {
                            #(#variant_clones,)*
                        }
                    }
                }

                impl #impl_generics #FQDefault for #template_ident #type_generics #where_clause {
                    fn default() -> Self {
                        #variant_default_ident
                    }
                }
            }
        }
        Data::Union(_) => panic!("Union types are not supported yet."),
    };

    let mut unpin_where_clause = where_clause.cloned().unwrap_or_else(|| WhereClause {
        where_token: <Token![where]>::default(),
        predicates: Punctuated::new(),
    });

    unpin_where_clause
        .predicates
        .push(parse_quote! { for<'a> [()]: #bevy_ecs::template::SpecializeFromTemplate });

    TokenStream::from(quote! {
        impl #impl_generics #bevy_ecs::template::FromTemplate for #type_ident #type_generics #where_clause {
            type Template = #template_ident #type_generics;
        }

        impl #impl_generics ::core::marker::Unpin for #type_ident #type_generics #unpin_where_clause {}

View on GitHub (pinned to 396ca72708)

Solutions

  1. Convert the union into an enum (one variant per alternate layout) and keep the derive
  2. Refactor the union into a struct if only one interpretation is active at a time
  3. Drop `#[derive(FromTemplate)]` from the union and hand-implement the `Template` trait for a separate template type until union support lands

Example fix

// before
#[derive(FromTemplate)]
union RawValue {
    int: i32,
    float: f32,
}

// after
#[derive(FromTemplate)]
enum RawValue {
    Int(i32),
    Float(f32),
}
Defensive patterns

Strategy: validation

Validate before calling

# compile-time macro panics surface here; run in CI before runtime tests
cargo check --workspace --all-targets

# review every union for accidental derive attributes
rg -n -B4 '^[[:space:]]*union ' crates/

Prevention

When it happens

Trigger: Placing `#[derive(FromTemplate)]` on a `union` item. The derive macro expands, matches the union arm, and panics during compilation of the invoking crate.

Common situations: Trying the newer template/prefab-style workflow on FFI or bit-manipulation types declared as unions; blanket-applying the derive while refactoring a module; porting code from another engine where unions were the natural shape.

Related errors


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