{"record":{"id":"3e495a76d6563470","repo":"BoundaryML/baml","slug":"variant-requires-an-explicit-discriminant-to-stabilize-its","errorCode":null,"errorMessage":"variant `{}` requires an explicit discriminant to stabilize its Borsh tag","messagePattern":"variant `(.+?)` requires an explicit discriminant to stabilize its Borsh tag","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"baml_language/crates/baml_type_macros/src/parse.rs","lineNumber":433,"sourceCode":"                \"variant `{}` must declare exactly one `#[axis(..)]`\",\n                variant.ident\n            ),\n        )\n    })?;\n    let axis = axis_index(&axis_ident)?;\n    let discriminant = match variant.discriminant.as_ref().map(|(_, expr)| expr) {\n        Some(syn::Expr::Lit(syn::ExprLit {\n            lit: syn::Lit::Int(value),\n            ..\n        })) => value.base10_parse::<u8>()?,\n        Some(expr) => {\n            return Err(syn::Error::new_spanned(\n                expr,\n                \"type-family variants require an explicit u8 integer discriminant\",\n            ));\n        }\n        None => {\n            return Err(syn::Error::new(\n                span,\n                format!(\n                    \"variant `{}` requires an explicit discriminant to stabilize its Borsh tag\",\n                    variant.ident\n                ),\n            ));\n        }\n    };\n    // A variant need not carry a `TyAttr`: a template-only leaf (`TypeArgRef`)\n    // is pure structure with no streaming metadata. The generated\n    // `attr()`/`with_attr()` accessors fall back to `TyAttr::EMPTY` / identity\n    // for them (see `emit::attr_arm`). `has_attr` records which case applies so\n    // the accessor arms don't need to re-derive it.\n    let has_attr = carries_ty_attr(&variant.fields);\n    Ok(MVariant {\n        attrs,\n        ident: variant.ident,\n        fields: variant.fields,","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/baml_type_macros/src/parse.rs#L415-L451","documentation":"Type-family variants must carry an explicit `u8` integer discriminant so the Borsh serialization tag is stable. `resolve_variant` raises this error when the discriminant expression is absent (the `None` arm). A present but non-u8-literal discriminant gets the separate 'type-family variants require an explicit u8 integer discriminant' error.","triggerScenarios":"Declaring a variant with `#[axis(..)]` but no explicit discriminant like `= 3`; the discriminant match on the variant's expr returns `None`.","commonSituations":"Adding a variant and omitting the discriminant because plain Rust enums allow implicit numbering; implicit tags would break wire compatibility if variants are reordered.","solutions":["Add an explicit integer discriminant to the variant, e.g. `Variant = 4`.","Pick an unused u8 value consistent with the other variants' numbering.","Never reuse a discriminant already assigned to another variant."],"exampleFix":"// before\n#[axis(Shape)]\nVariant { x: u32 },\n// after\n#[axis(Shape)]\nVariant = 5 { x: u32 },","handlingStrategy":"validation","validationCode":"// every variant needs an explicit u8 discriminant\n// enum TypeFamily { A = 0, B = 1, /* ... */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write `= N` discriminants; never rely on implicit numbering","Assign new variants the next free u8 and record the mapping","Remember discriminants are wire tags — treat changes as breaking"],"tags":["proc-macro","compile-time","serialization","borsh","rust"],"backgroundTag":"missing-required-argument","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}