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
- Move `#[derive(ProtoEnumSerde)]` onto the enum declaration; ensure the enum is `#[repr(i32)]` (otherwise the derive silently emits nothing).
- 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.
- 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
- Attach ProtoEnumSerde only to `#[repr(i32)]` enum declarations
- Keep derive lists adjacent to the item they belong to
- Remember: enums without #[repr(i32)] silently get no impls
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
- Unnamed field not supported
- Unsupported enum field type shape; expected i32, Option<i32>
- ProtoNew only supports structs with named fields
- ProtoNew can only be derived for structs
- `name` set multiple times.
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/5c17c9ee0bbf407f.
Report an issue: GitHub.