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

ProtoEnumSerde can only be derived for enums

Error message

ProtoEnumSerde can only be derived for enums

What it means

The ProtoEnumSerde derive generates serde Serialize/Deserialize impls that round-trip a prost i32-backed enum through its proto string name. It only applies to Rust enums, so the macro rejects any input that is a struct or union with this compile-time error.

Source

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

fn vec_path_for(ty: &Type) -> proc_macro2::TokenStream {
    // Preserve the original vector path (Vec or ::prost::alloc::vec::Vec)
    if let Type::Path(tp) = ty {
        let segments = tp.path.segments.clone();
        if let Some(last) = segments.last()
            && last.ident == "Vec"
        {
            let path = &tp.path;
            return quote! { #path };
        }
    }
    quote! { ::prost::alloc::vec::Vec }
}

fn impl_proto_enum_serde(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
    match input.data {
        Data::Enum(_) => {}
        _ => {
            return Err(syn::Error::new(
                input.span(),
                "ProtoEnumSerde can only be derived for enums",
            ));
        }
    }

    if !has_repr_i32(input) {
        // Not an i32-backed enum; skip deriving anything per request.
        return Ok(quote! {});
    }

    let enum_ident = &input.ident;

    let ser_impl = quote! {
        impl ::serde::Serialize for #enum_ident {
            fn serialize<S>(&self, serializer: S) -> ::core::result::Result<S::Ok, S::Error>
            where
                S: ::serde::Serializer,

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Move `#[derive(ProtoEnumSerde)]` onto the enum declaration; ensure the enum is `#[repr(i32)]` (otherwise the derive silently emits nothing).
  2. If the item really is a struct, remove the ProtoEnumSerde derive and derive serde's `Serialize`/`Deserialize` directly (e.g. with `#[serde(rename_all = ...)]`) instead.
  3. For prost-generated enums, rely on the generated `as_str_name()`/`from_str_name()` and derive ProtoEnumSerde only on the wrapping enum.

Example fix

// before
#[derive(ProtoEnumSerde)]
pub struct Kind;

// after
#[derive(ProtoEnumSerde)]
#[repr(i32)]
pub enum Kind {
    Unspecified = 0,
    Active = 1,
}
Defensive patterns

Strategy: type-guard

Validate before calling

// only enums qualify; verify before deriving
// enum Kind { ... } with #[repr(i32)] for the serde impls to be emitted

Type guard

macro_rules! assert_enum {
    (enum $name:ident { $($t:tt)* }) => {};
    ($other:tt) => { compile_error!("ProtoEnumSerde can only be derived for enums"); };
}

Prevention

When it happens

Trigger: Annotating `#[derive(ProtoEnumSerde)]` on a struct or union instead of an enum; accidentally placing the derive on the wrong item after a refactor that converted an enum to a struct.

Common situations: Copy-pasting derive lists between type declarations; mass renames/refactors where an enum became a struct with associated constants; IDE auto-import attaching the derive to the wrong block.

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/5c17c9ee0bbf407f. Report an issue: GitHub.