swc-project/swc · error

unsupported discriminant type

Error message

unsupported discriminant type

What it means

The generated CBOR codec indexes each variant with a running u32 counter; an explicit discriminant is honored only when it is an integer literal (syn::Lit::Int) that base10_parse can read as u32 — the macro does no const evaluation. `A = SOME_CONST`, `A = -1`, or any other expression hits `Some(_) => panic!("unsupported discriminant type")`. Values that overflow u32 additionally fail inside the following unwrap().

Source

Thrown at crates/ast_node/src/encoding/decode.rs:160

                        _ => panic!("named enum unsupported"),
                    }
                });

            if matches!(enum_type, EnumType::Struct) {
                assert!(
                    unknown_arm.is_none(),
                    "struct enum does not allow unknown variants"
                );
            }

            let mut discriminant: u32 = 0;
            let fields = iter
                .map(|field| -> syn::Arm {
                    match field.discriminant.as_ref() {
                        Some((_, syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(lit), .. }))) => {
                            discriminant = lit.base10_parse::<u32>().unwrap();
                        },
                        Some(_) => panic!("unsupported discriminant type"),
                        None => (),
                    };
                    discriminant += 1;
                    let idx = discriminant as u64;
                    let name = &field.ident;

                    assert!(!is_unknown(&field.attrs), "unknown member must be first");

                    match enum_type {
                        EnumType::Unit => {
                            assert!(is_with(&field.attrs).is_none(), "unit member is not allowed with type");
                            syn::parse_quote!{
                                #idx => #ident::#name,
                            }
                        },
                        EnumType::One => {
                            let val_ty = &field.fields.iter().next().unwrap().ty;
                            let value: syn::Expr = match is_with(&field.attrs) {

View on GitHub (pinned to 5176682b65)

Solutions

  1. Inline the value as an integer literal: `Num = 3`.
  2. Or remove explicit discriminants and let the macro assign sequential indices.
  3. Keep external consumers in sync by asserting the encoded tag value in a test instead of sharing a const into the enum definition.

Example fix

// before
const KIND_NUM: u32 = 3;
enum Tagged {
    Str = 1,
    Num = KIND_NUM,
}

// after — plain u32 literals
enum Tagged {
    Str = 1,
    Num = 3,
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: derive(Decode) on an enum where a variant discriminant is a path/constant, a negative number, or any non-literal expression instead of a plain u32 integer literal.

Common situations: Sharing discriminant constants between the wire protocol and Rust code; refactoring magic numbers into consts and forgetting the macro only accepts literals.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/d42d210f396743bb. Report an issue: GitHub.