swc-project/swc · error

swc does not support record expressions

Error message

swc does not support record expressions

What it means

Swcify in swc_estree_compat maps each swc_estree_ast node to an swc_ecma_ast node. RecordExpression (the `{| a: 1 |}` literal from the Records & Tuples proposal) has no counterpart in SWC's AST, so its impl returns the uninhabited Never type and panics. This is an intentional hard failure marking the syntax as unrepresentable.

Source

Thrown at crates/swc_estree_compat/src/swcify/expr.rs:1130

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support do expressions")
    }
}

impl Swcify for PipelinePrimaryTopicReference {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support `PipelinePrimaryTopicReference`")
    }
}

impl Swcify for RecordExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support record expressions")
    }
}

impl Swcify for TupleExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support tuple expressions")
    }
}

impl Swcify for ModuleExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support module expressions")
    }
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Remove @babel/plugin-syntax-record-and-tuple (or the parser flag) so `{| |}` record literals are never produced
  2. Lower records to plain object expressions (or esbuild/babel output) before feeding the AST to swcify
  3. Parse the source with swc_ecma_parser, which rejects or handles syntax according to its own feature set
  4. Pre-validate the ESTree JSON for `type: "RecordExpression"` nodes and fail with a clear diagnostic instead of panicking

Example fix

// before
const rec = {| a: 1 |};  // parsed by babel w/ record-and-tuple syntax
ast.swcify(&ctx);         // panics: swc does not support record expressions

// after
const rec = { a: 1 };    // plain object literal
ast.swcify(&ctx);         // ok
Defensive patterns

Strategy: type-guard

Validate before calling

let mut bad = Vec::new();
find_unsupported(&estree_json, &mut bad); // same walk as error 200
if bad.iter().any(|t| t == "RecordExpression") {
    return Err("record literals ({| ... |}) are not supported by swcify".into());
}

Type guard

fn is_unsupported_estree_type(t: &str) -> bool {
    matches!(
        t,
        "RecordExpression" | "TupleExpression" | "PipelinePrimaryTopicReference"
            | "BindExpression" | "DoExpression" | "ModuleExpression"
    )
}

Try / catch

let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    estree_expr.swcify(&ctx)
}));
if out.is_err() {
    // map to a diagnostic naming the unsupported node instead of aborting
    return Err("swcify cannot convert this ESTree tree (unsupported proposal syntax)".into());
}

Prevention

When it happens

Trigger: Calling `.swcify(ctx)` on an ESTree tree containing a RecordExpression node, i.e. code parsed with @babel/plugin-syntax-record-and-tuple (or an equivalent parser plugin) producing `{| key: value |}` literals that are then converted to SWC.

Common situations: Babel-first pipelines that keep proposal syntax and hand the AST to SWC via swc_estree_compat; mixing parser feature flags (record-and-tuple enabled upstream) with SWC conversion; exploratory tooling that accepts arbitrary ESTree JSON.

Related errors


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