{"record":{"id":"0cade84803c8e03d","repo":"dbt-labs/dbt-core","slug":"unsupported-enum-field-type-shape-expected-i32-o","errorCode":null,"errorMessage":"Unsupported enum field type shape; expected i32, Option<i32>, or Vec<i32>","messagePattern":"Unsupported enum field type shape; expected i32, Option<i32>, or Vec<i32>","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/proto-rust-macros/src/lib.rs","lineNumber":217,"sourceCode":"\n    // Option<i32>\n    if let Some(inner) = extract_generic(field_ty, \"Option\")\n        && is_i32(inner)\n    {\n        let param_ty = quote! { ::core::option::Option<#enum_path> };\n        let init = quote! { #param_ident.map(|v| v as i32) };\n        return Ok((param_ty, init));\n    }\n\n    // Vec<i32> and ::prost::alloc::vec::Vec<i32>\n    if is_vec_of_i32(field_ty) {\n        let vec_path = vec_path_for(field_ty);\n        let param_ty = quote! { #vec_path<#enum_path> };\n        let init = quote! { #param_ident.into_iter().map(|v| v as i32).collect() };\n        return Ok((param_ty, init));\n    }\n\n    Err(syn::Error::new(\n        field_ty.span(),\n        \"Unsupported enum field type shape; expected i32, Option<i32>, or Vec<i32>\",\n    ))\n}\n\nfn is_i32(ty: &Type) -> bool {\n    match ty {\n        Type::Path(tp) => {\n            if let Some(seg) = tp.path.segments.last() {\n                seg.ident == \"i32\" && matches!(seg.arguments, PathArguments::None)\n            } else {\n                false\n            }\n        }\n        _ => false,\n    }\n}\n","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/proto-rust-macros/src/lib.rs#L199-L235","documentation":"When a prost field carries `#[prost(enumeration = \"...\")]`, the ProtoNew derive replaces the field's i32-based type with the enum type in the generated `new()` signature. It only knows three shapes: `i32`, `Option<i32>`, and `Vec<i32>` (or prost's `::prost::alloc::vec::Vec<i32>`); any other type shape for an enumeration field fails at compile time.","triggerScenarios":"Deriving ProtoNew on a struct whose `#[prost(enumeration=\"X\")]` field is typed as e.g. `Box<i32>`, `HashMap<..>`, `Option<Vec<i32>>`, a type alias to i32, or a fully-qualified path the shape matchers (`is_i32`, `extract_generic`, `is_vec_of_i32`) do not recognize.","commonSituations":"prost-generated code where the enumeration is wrapped in additional containers (repeated+optional combos, boxed fields); hand-written structs using type aliases like `type Int32 = i32;` (alias names break the `i32` ident check); upgrading prost and getting a different Vec path spelling.","solutions":["Change the field type to one of the supported shapes: `i32`, `Option<i32>`, or `Vec<i32>` (prost's default shapes for optional/repeated enumeration fields).","Change the generated `new()` parameter to accept the enum type manually: drop ProtoNew for that struct and hand-write the constructor.","Extend `map_enum_param_and_init` in crates/proto-rust-macros/src/lib.rs to recognize the additional shape (e.g. unwrap type aliases or new wrappers) before matching."],"exampleFix":"// before\n#[derive(ProtoNew)]\npub struct Msg {\n    #[prost(enumeration = \"Kind\")]\n    pub kind: Option<Option<i32>>,\n}\n\n// after\n#[derive(ProtoNew)]\npub struct Msg {\n    #[prost(enumeration = \"Kind\")]\n    pub kind: Option<i32>,\n}","handlingStrategy":"type-guard","validationCode":"// before deriving, confirm enum fields use one of:\n// i32 | Option<i32> | Vec<i32> | ::prost::alloc::vec::Vec<i32>\nfn is_supported_enum_shape(ty: &str) -> bool {\n    matches!(ty, \"i32\" | \"Option<i32>\" | \"Vec<i32>\" | \"::prost::alloc::vec::Vec<i32>\")\n}","typeGuard":"fn is_i32(ty: &syn::Type) -> bool {\n    matches!(ty, syn::Type::Path(tp)\n        if tp.path.segments.last().map_or(false, |s| s.ident == \"i32\"))\n}","tryCatchPattern":null,"preventionTips":["Keep prost enumeration fields in their default shapes (i32/Option<i32>/Vec<i32>)","Avoid type aliases on enumeration field types (aliases break ident matching)","Test the generated `new()` in a compile-fail/doctest when adding new enum fields"],"tags":["proc-macro","derive-macro","type-mismatch","rust","protobuf"],"backgroundTag":"type-mismatch","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}