swc-project/swc · error · TypeError

${objectType} can't have a .${name} property.

Error message

${objectType} can't have a .${name} property.

What it means

The second copy of the tag-parsing logic in crates/ast_node/src/enum_deserialize.rs (the block that builds str_pat/bytes_pat for the deserialization match arms) parses #[tag(..)] contents with syn::parse2::<VariantAttr>().expect("failed to parse #[tag] attribute"). The accepted grammar is a comma-terminated list of literals only, so anything else inside the parentheses panics the #[derive(DeserializeEnum)] / #[ast_node] macro at compile time with this message.

Source

Thrown at crates/swc_ecma_transforms_base/src/helpers/generated/_decorate.rs:252

    return obj;
}
function _toClassDescriptor(obj) {
    var kind = String(obj.kind);
    if (kind !== "class") {
        throw new TypeError("A class descriptor's .kind property must be \"class\", but a decorator" + " created a class descriptor with .kind \"" + kind + "\"");
    }
    _disallowProperty(obj, "key", "A class descriptor");
    _disallowProperty(obj, "placement", "A class descriptor");
    _disallowProperty(obj, "descriptor", "A class descriptor");
    _disallowProperty(obj, "initializer", "A class descriptor");
    _disallowProperty(obj, "extras", "A class descriptor");
    var finisher = _optionalCallableProperty(obj, "finisher");
    var elements = _toElementDescriptors(obj.elements);

    return { elements: elements, finisher: finisher };
}
function _disallowProperty(obj, name, objectType) {
    if (obj[name] !== undefined) throw new TypeError(objectType + " can't have a ." + name + " property.");
}
function _optionalCallableProperty(obj, name) {
    var value = obj[name];
    if (value !== undefined && typeof value !== "function") {
        throw new TypeError("Expected '" + name + "' to be a function");
    }

    return value;
}
function _runClassFinishers(constructor, finishers) {
    for (var i = 0; i < finishers.length; i++) {
        var newConstructor = (0, finishers[i])(constructor);
        if (newConstructor !== undefined) {
            if (typeof newConstructor !== "function") throw new TypeError("Finishers must return a constructor.");
            constructor = newConstructor;
        }
    }

View on GitHub (pinned to 5176682b65)

Solutions

  1. Use string literals for tags: #[tag("TagName")] or #[tag("Tag1", "Tag2")] with comma separators.
  2. Do not nest attribute syntax or use expressions/macros inside #[tag(..)].
  3. After fixing syntax, confirm every variant still has at least one tag or you will hit the 'All #[ast_node] enum variants have one or more tag' assert next.
  4. Remember "*" as the sole tag is the wildcard arm, which follows a different code path.

Example fix

// before
#[tag(List)]
Expr(List),

// after
#[tag("List")]
Expr(List),
Defensive patterns

Strategy: validation

Validate before calling

// Same rule in the str/bytes pattern block: literals, comma-separated.
// Generator-side guard before emitting variants:
assert!(
    tags.iter().all(|t| !t.contains('"') && !t.is_empty()),
    "tags must be plain names; they will be emitted as quoted literals"
);

Prevention

When it happens

Trigger: A #[tag] attribute on an enum variant whose inner tokens are not literals separated by commas: #[tag(Something)], #[tag(concat("a"))], #[tag("a"; "b")]. Reaching the str_pat/bytes_pat block also requires the variant to have exactly one unnamed field, as asserted just above.

Common situations: Defining swc-compatible AST enums with serde-style tag syntax; copy-pasting attribute lists from other proc macros that accept expressions; automated codemods rewriting attribute contents and dropping the quotes.

Related errors


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