{"record":{"id":"248ebc441160ad6e","repo":"BoundaryML/baml","slug":"bamlserde-cannot-be-derived-for-enums-use-serde-untagged-on","errorCode":null,"errorMessage":"BamlSerde cannot be derived for enums, use `#[serde(untagged)]` on dynamic instead.","messagePattern":"BamlSerde cannot be derived for enums, use `#\\[serde\\(untagged\\)\\]` on dynamic instead\\.","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"languages/rust/baml-macros/src/baml_serde.rs","lineNumber":18,"sourceCode":"use proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::{Data, DataEnum, DeriveInput, Ident, Result};\n\nuse crate::shared::{ContainerAttrs, VariantAttrs};\n\npub(crate) fn derive_serde(input: &DeriveInput) -> Result<TokenStream> {\n    let container_attrs = ContainerAttrs::from_attrs(&input.attrs)?;\n\n    match &input.data {\n        Data::Struct(..) => Err(syn::Error::new(\n            Span::call_site(),\n            \"BamlSerde cannot be derived for structs, use `#[serde(flatten)]` on dynamic instead.\",\n        )),\n        Data::Enum(data_enum) if container_attrs.union => {\n            derive_serde_union(data_enum, &input.ident)\n        }\n        Data::Enum(..) => Err(syn::Error::new(\n            Span::call_site(),\n            \"BamlSerde cannot be derived for enums, use `#[serde(untagged)]` on dynamic instead.\",\n        )),\n        Data::Union(..) => Err(syn::Error::new(\n            Span::call_site(),\n            \"Rust unions are not supported for this derive macro.\",\n        )),\n    }\n}\n\nfn derive_serde_union(data: &DataEnum, ident: &Ident) -> Result<TokenStream> {\n    let name = ident.to_string();\n\n    let mut literal_serde = Vec::new();\n\n    for variant in &data.variants {\n        let variant_attrs = VariantAttrs::from_attrs(&variant.attrs)?;\n        let variant_ident = &variant.ident;","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/languages/rust/baml-macros/src/baml_serde.rs#L1-L36","documentation":"Compile-time error from the `BamlSerde` derive macro: plain enums (without the `union` container attribute) are not supported. BAML union enums must be declared as untagged unions via `#[serde(untagged)]` (plus the union container attr) so the derive emits union serde logic. Emitted by `derive_serde` when input is `Data::Enum` without `container_attrs.union`.","triggerScenarios":"Applying `#[derive(BamlSerde)]` to an enum lacking the union container attribute, e.g. `#[derive(BamlSerde)] enum E { A, B }` with no `#[serde(untagged)]`/union attr.","commonSituations":"Deriving BamlSerde on regular tagged enums; forgetting to mark the enum as a union when porting from serde-style enums.","solutions":["Mark the enum as a union: add `#[serde(untagged)]` and the BAML union container attribute so it routes to `derive_serde_union`","Use plain `serde` derives if the enum is not a BAML union","Restructure as a struct with a flattened dynamic field if the data is not a union"],"exampleFix":"// before\n#[derive(BamlSerde)]\nenum Shape { Circle, Square }\n// after\n#[serde(untagged)]\n#[derive(BamlSerde)]\n#[baml(union = true)]\nenum Shape { Circle(f64), Square { side: f64 } }","handlingStrategy":"type-guard","validationCode":"// compile-time: ensure enums carry #[serde(untagged)] and the union container attr","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always mark BAML union enums as untagged","Verify container attribute is present before deriving BamlSerde","Run cargo check in CI to catch derive misuse"],"tags":["rust","derive-macro","serde","enum","compile-time"],"backgroundTag":"unsupported-enum-value","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}