dbt-labs/dbt-core · error · syn::Error

Unnamed field not supported

Error message

Unnamed field not supported

What it means

The ProtoNew derive macro generates a `new()` constructor from a struct's fields, and it requires every field to be named so it can emit a matching named parameter. It is a compile-time (proc-macro) error raised when the derived struct contains tuple-style or unit fields, which have no identifier to turn into a constructor argument.

Source

Thrown at crates/proto-rust-macros/src/lib.rs:69

        },
        _ => {
            return Err(syn::Error::new(
                input.span(),
                "ProtoNew can only be derived for structs",
            ));
        }
    };

    // Build parameter list and field initializers
    let mut params = Vec::new();
    let mut inits = Vec::new();
    let mut arg_docs: Vec<String> = Vec::new();

    for field in fields {
        let field_ident = field
            .ident
            .clone()
            .ok_or_else(|| syn::Error::new(field.span(), "Unnamed field not supported"))?;

        let is_enum = find_prost_enumeration_attr(&field.attrs)?;

        let param_ident = field_ident.clone();

        // Collect doc for this field
        if let Some(doc) = extract_field_doc(&field.attrs) {
            let name = field_ident.to_string();
            let arg_doc = format!("* `{name}` - {doc}");
            arg_docs.push(arg_doc);
        }

        if let Some(enum_path) = is_enum {
            // Replace i32 in the outer shape with enum path for the parameter type,
            // and create an initializer that converts enum(s) back to i32.
            let (param_ty_tokens, init_expr) =
                map_enum_param_and_init(&field.ty, &enum_path, &param_ident)?;
            params.push(quote! { #param_ident: #param_ty_tokens });

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Convert the struct to use named fields: `struct Msg(i32);` -> `struct Msg { value: i32 }`.
  2. If the type is a genuine newtype wrapper, remove `#[derive(ProtoNew)]` and implement `new()` manually.
  3. Keep prost-generated message structs untouched and derive ProtoNew only on structs produced from .proto definitions, which always have named fields.

Example fix

// before
#[derive(ProtoNew)]
struct MyMessage(i32);

// after
#[derive(ProtoNew)]
struct MyMessage {
    value: i32,
}
Defensive patterns

Strategy: validation

Validate before calling

// compile-time check: derive fails fast if any field is unnamed
fn assert_named_fields<T>() {}
// Ensure struct shape before deriving:
// struct Msg { id: i32 }  // all fields must be `name: Type`

Prevention

When it happens

Trigger: Applying #[derive(ProtoNew)] to a struct declared with unnamed fields (e.g. `struct Msg(i32);`) or unit variants/fields (`struct Msg;`) instead of named fields (`struct Msg { id: i32 }`).

Common situations: Hand-written prost message structs that mimic tuple structs; copied Rust code (like newtype wrappers) that happens to carry the derive; code generated from a .proto with unusual shapes then hand-edited into tuple form.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/627385b0e3a30b07. Report an issue: GitHub.