swc-project/swc · error

#[tag] attribute must be in form of #[tag(..)]

Error message

#[tag] attribute must be in form of #[tag(..)]

What it means

The DeserializeEnum derive (applied automatically to every #[ast_node(...)] enum) implements untagged serde deserialization by matching the serialized "type" field against per-variant #[tag("...")] attributes. Attribute parsing accepts only the list form (syn::Meta::List); writing `#[tag = "Super"]` (name=value) or a bare `#[tag]` resolves to a different Meta shape and panics at this first expansion pass, with the message stating the exact expected form #[tag(..)].

Source

Thrown at crates/ast_node/src/enum_deserialize.rs:65

                        );

                        fields.unnamed.last().unwrap().ty.clone()
                    }
                    _ => {
                        unreachable!("#[ast_node] enum cannot contain named fields or unit variant")
                    }
                };
                let tags = variant
                    .attrs
                    .iter()
                    .filter_map(|attr| -> Option<VariantAttr> {
                        if !is_attr_name(attr, "tag") {
                            return None;
                        }
                        let tokens = match &attr.meta {
                            Meta::List(meta) => meta.tokens.clone(),
                            _ => {
                                panic!("#[tag] attribute must be in form of #[tag(..)]")
                            }
                        };
                        let tags = parse2(tokens).expect("failed to parse #[tag] attribute");

                        Some(tags)
                    })
                    .flat_map(|v| v.tags)
                    .collect::<Punctuated<_, token::Comma>>();

                assert!(
                    !tags.is_empty(),
                    "All #[ast_node] enum variants have one or more tag"
                );

                // TODO: Clean up this code
                if tags.len() == 1
                    && match tags.first() {
                        Some(Lit::Str(s)) => &*s.value() == "*",

View on GitHub (pinned to 5176682b65)

Solutions

  1. Use list syntax with string literals: `#[tag("Super")]`; repeat the attribute to give a variant multiple tags.
  2. Use the wildcard `#[tag("*")]` when one variant should absorb many types.
  3. Ensure every variant has at least one tag — the very next assert requires it.

Example fix

// before
#[ast_node("Ref")]
enum Ref {
    #[tag = "Super"]
    Super(SuperProp),
}

// after
#[ast_node("Ref")]
enum Ref {
    #[tag("Super")]
    Super(SuperProp),
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Defining an enum with #[ast_node("SomeType")] (or #[derive(DeserializeEnum)]) where a variant's tag attribute is `#[tag = "..."]`, a bare `#[tag]`, or any non-parenthesized form.

Common situations: Writing custom AST nodes for swc transforms/plugins; IDEs auto-completing serde-style `tag = "..."` attributes; copying serde attribute syntax into swc enums.

Related errors


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