{"record":{"id":"26b60b16cbc7553e","repo":"dbt-labs/dbt-core","slug":"protonew-only-supports-structs-with-named-fields","errorCode":null,"errorMessage":"ProtoNew only supports structs with named fields","messagePattern":"ProtoNew only supports structs with named fields","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/proto-rust-macros/src/lib.rs","lineNumber":46,"sourceCode":"/// and the initializer converts the enum value(s) back to i32 as needed.\n#[proc_macro_derive(ProtoNew, attributes(prost))]\npub fn derive_proto_new(input: TokenStream) -> TokenStream {\n    let input = parse_macro_input!(input as DeriveInput);\n\n    match impl_proto_new(&input) {\n        Ok(ts) => ts.into(),\n        Err(err) => err.to_compile_error().into(),\n    }\n}\n\nfn impl_proto_new(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {\n    let struct_ident = &input.ident;\n\n    let fields = match &input.data {\n        Data::Struct(s) => match &s.fields {\n            Fields::Named(named) => &named.named,\n            _ => {\n                return Err(syn::Error::new(\n                    s.fields.span(),\n                    \"ProtoNew only supports structs with named fields\",\n                ));\n            }\n        },\n        _ => {\n            return Err(syn::Error::new(\n                input.span(),\n                \"ProtoNew can only be derived for structs\",\n            ));\n        }\n    };\n\n    // Build parameter list and field initializers\n    let mut params = Vec::new();\n    let mut inits = Vec::new();\n    let mut arg_docs: Vec<String> = Vec::new();\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/proto-rust-macros/src/lib.rs#L28-L64","documentation":"The ProtoNew derive macro (impl_proto_new, invoked via derive_proto_new) only supports structs whose fields are all named (Fields::Named). Applying #[derive(ProtoNew)] to a tuple struct or unit struct makes the macro return a syn::Error at the fields' span, producing a compile-time error. Named fields are required because the macro generates a constructor keyed by field name.","triggerScenarios":"Adding `#[derive(ProtoNew)]` to a tuple struct like `struct Foo(u32);` or a unit struct like `struct Foo;`.","commonSituations":"Copy-pasting the derive onto protos/enums-as-newtypes or wrapper tuple structs; refactoring a named-field struct into a tuple struct while keeping the derive.","solutions":["Convert the struct to use named fields","Remove the ProtoNew derive from the tuple/unit struct and construct it directly","If ProtoNew should support tuple structs, extend the macro to handle Fields::Unnamed"],"exampleFix":"// before\n#[derive(ProtoNew)]\nstruct Column(u32, String);\n// after\n#[derive(ProtoNew)]\nstruct Column {\n    index: u32,\n    name: String,\n}","handlingStrategy":"validation","validationCode":"// Compile-time: the derive itself is the guard; prefer validating struct shape in CI\n// cargo check fails with this message when applied to tuple/unit structs","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only apply #[derive(ProtoNew)] to structs with named fields","Read the compile error span — it points at the offending fields declaration","If wrapping values, use a named-field struct with one field instead of a tuple struct"],"tags":["derive-macro","protobuf","compile-time","proc-macro"],"backgroundTag":"unsupported-derive-target","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"}