{"record":{"id":"9bd6d498db674212","repo":"bevyengine/bevy","slug":"union-types-are-not-supported-yet","errorCode":null,"errorMessage":"Union types are not supported yet.","messagePattern":"Union types are not supported yet\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/bevy_ecs/macros/src/template.rs","lineNumber":305,"sourceCode":"                            #(#variant_builds,)*\n                        })\n                    }\n\n                    fn clone_template(&self) -> Self {\n                        match self {\n                            #(#variant_clones,)*\n                        }\n                    }\n                }\n\n                impl #impl_generics #FQDefault for #template_ident #type_generics #where_clause {\n                    fn default() -> Self {\n                        #variant_default_ident\n                    }\n                }\n            }\n        }\n        Data::Union(_) => panic!(\"Union types are not supported yet.\"),\n    };\n\n    let mut unpin_where_clause = where_clause.cloned().unwrap_or_else(|| WhereClause {\n        where_token: <Token![where]>::default(),\n        predicates: Punctuated::new(),\n    });\n\n    unpin_where_clause\n        .predicates\n        .push(parse_quote! { for<'a> [()]: #bevy_ecs::template::SpecializeFromTemplate });\n\n    TokenStream::from(quote! {\n        impl #impl_generics #bevy_ecs::template::FromTemplate for #type_ident #type_generics #where_clause {\n            type Template = #template_ident #type_generics;\n        }\n\n        impl #impl_generics ::core::marker::Unpin for #type_ident #type_generics #unpin_where_clause {}\n","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_ecs/macros/src/template.rs#L287-L323","documentation":"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.","triggerScenarios":"Placing `#[derive(FromTemplate)]` on a `union` item. The derive macro expands, matches the union arm, and panics during compilation of the invoking crate.","commonSituations":"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.","solutions":["Convert the union into an enum (one variant per alternate layout) and keep the derive","Refactor the union into a struct if only one interpretation is active at a time","Drop `#[derive(FromTemplate)]` from the union and hand-implement the `Template` trait for a separate template type until union support lands"],"exampleFix":"// before\n#[derive(FromTemplate)]\nunion RawValue {\n    int: i32,\n    float: f32,\n}\n\n// after\n#[derive(FromTemplate)]\nenum RawValue {\n    Int(i32),\n    Float(f32),\n}","handlingStrategy":"validation","validationCode":"# compile-time macro panics surface here; run in CI before runtime tests\ncargo check --workspace --all-targets\n\n# review every union for accidental derive attributes\nrg -n -B4 '^[[:space:]]*union ' crates/","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply FromTemplate only to structs and enums","Keep FFI/bitfield unions in a module without bevy derives","Add the derive per type deliberately instead of via shared derive-all macros"],"tags":["rust","bevy","ecs","proc-macro","compile-time","union"],"backgroundTag":"derive-macro-unsupported-type","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T20:17:18.057Z"}