swc-project/swc · error

unknown member must be a tag and a value

Error message

unknown member must be a tag and a value

What it means

The #[encoding(unknown)] variant is swc's forward-compatibility escape hatch: unknown CBOR tags on the wire decode into it. The macro only generates code for two shapes — one unnamed field (bare tag: Unknown(u32)) and two unnamed fields (tag + value: Unknown(u32, T), where it decodes fields.unnamed[1]). Any other arity (zero or three-plus unnamed fields) cannot be mapped, so expansion panics with 'unknown member must be a tag and a value'.

Source

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

                                assert_eq!(enum_type, EnumType::Unit);
                                syn::parse_quote! {
                                    tag => #ident::#name(tag),
                                }
                            }
                            2 => {
                                assert_eq!(enum_type, EnumType::One);
                                let val_ty = &fields.unnamed[1].ty;
                                syn::parse_quote! {
                                    tag => {
                                        let tag: u32 = tag.try_into().map_err(|_| cbor4ii::core::error::DecodeError::CastOverflow {
                                             name: &"unknown-tag",
                                        })?;
                                        let val = <#val_ty as cbor4ii::core::dec::Decode<'_>>::decode(reader)?;
                                        #ident::#name(tag, val)
                                    },
                                }
                            }
                            _ => panic!("unknown member must be a tag and a value"),
                        },
                        _ => 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();

View on GitHub (pinned to 5176682b65)

Solutions

  1. Declare the unknown variant with exactly `#[encoding(unknown)] Unknown(u32)` for all-unit enums, or `#[encoding(unknown)] Unknown(u32, YourUnknownType)` for payload-carrying enums.
  2. Prefer #[ast_node(...)] over manual derives so the Unknown variant is generated for you.
  3. Place the unknown variant first — a later assert also requires it to precede tagged variants.

Example fix

// before
#[derive(Encode, Decode)]
enum Expr {
    #[encoding(unknown)]
    Unknown,
    Num { value: f64 },
}

// after — tag + value tuple
#[derive(Encode, Decode)]
enum Expr {
    #[encoding(unknown)]
    Unknown(u32, swc_common::unknown::Unknown),
    Num { value: f64 },
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Hand-writing derive(Encode/Decode) (not via #[ast_node]) on an enum and annotating a variant #[encoding(unknown)] whose shape is `Unknown`, `Unknown(u32, u32, u32)`, etc.

Common situations: Custom AST nodes for swc plugins or swc_ast_unknown builds; hand-porting the auto-generated Unknown variant and getting its arity wrong. #[ast_node] injects the correct Unknown(u32) / Unknown(u32, swc_common::unknown::Unknown) shapes itself, so this fires only for manual derives.

Related errors


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