diem/diem · error

#[derive(NumVariants)] can only be used on an enum

Error message

#[derive(NumVariants)] can only be used on an enum

What it means

This is a proc-macro compile-time error from the `num-variants` derive crate. `#[derive(NumVariants)]` generates a constant counting the enum's variants, so it is only valid on enums; applying it to a struct or union makes `compute_num_variants` emit a `syn::Error` at the item's span.

Source

Thrown at crates/num-variants/src/lib.rs:53

    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let num_variants = compute_num_variants(&input.data, input_span)?;

    let expanded = quote! {
        impl #impl_generics #name #ty_generics #where_clause {
            /// The number of variants in this enum.
            pub const #const_name: usize = #num_variants;
        }
    };

    Ok(expanded)
}

/// Computes the number of variants for an enum.
fn compute_num_variants(data: &Data, span: Span) -> Result<usize> {
    match data {
        Data::Enum(data) => Ok(data.variants.len()),
        Data::Struct(_) | Data::Union(_) => Err(Error::new(
            span,
            "#[derive(NumVariants)] can only be used on an enum",
        )),
    }
}

/// Computes the name of the constant.
fn compute_const_name(attrs: Vec<Attribute>) -> Result<Ident> {
    let mut const_names: Vec<_> = attrs
        .iter()
        .filter(|attr| attr.path.is_ident("num_variants"))
        .map(|attr| match attr.parse_meta() {
            Ok(Meta::NameValue(MetaNameValue {
                lit: Lit::Str(lit), ..
            })) => Ok((attr.span(), lit.parse::<Ident>()?)),
            _ => Err(Error::new(
                attr.span(),
                "must be of the form #[num_variants = \"FOO\"]",

View on GitHub (pinned to fc4714a8ea)

Solutions

  1. Remove `#[derive(NumVariants)]` from the struct/union
  2. Move the derive to an enum if that was the intent
  3. Hand-write the constant instead of deriving it

Example fix

// before
#[derive(NumVariants)]
pub struct MyStruct { a: u8 }
// after
pub struct MyStruct { a: u8 } // derive removed; NumVariants only works on enums
Defensive patterns

Strategy: type-guard

Validate before calling

// compile-time: only attach the derive to enums
enum MyEnum { A, B }

Type guard

// Verify at the item site: the annotated item must be `enum ...`, not struct/union

Prevention

When it happens

Trigger: Adding `#[derive(NumVariants)]` to a `struct` or `union` and compiling the crate.

Common situations: Copy-pasting the derive onto a struct by accident; refactoring an enum into a struct while leaving the derive in place.

Related errors


AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04). Data as JSON: /api/errors/11becbafab13228a. Report an issue: GitHub.