swc-project/swc · error

illegal conversion: Cannot convert {:?} to ExprOutput

Error message

illegal conversion: Cannot convert {:?} to ExprOutput

What it means

In the generic expression babelify (expr.rs:77-104), a Lit::JSXText literal has no Babel Expression counterpart — Babel only permits JSXText inside JSX text positions — so conversion panics. The SWC parser only ever produces JSXText inside JSX elements, so reaching this arm means a plugin, codemod, or hand-built AST placed JSXText into a plain expression slot; the code even carries a TODO asking whether this is really illegal.

Source

Thrown at crates/swc_estree_compat/src/babelify/expr.rs:97

                    Lit::Str(s) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::String(s.babelify(ctx)))),
                    ),
                    Lit::Bool(b) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::Boolean(b.babelify(ctx)))),
                    ),
                    Lit::Null(n) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::Null(n.babelify(ctx)))),
                    ),
                    Lit::Num(n) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::Numeric(n.babelify(ctx)))),
                    ),
                    Lit::BigInt(i) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::BigInt(i.babelify(ctx)))),
                    ),
                    Lit::Regex(r) => ExprOutput::Expr(
                        Box::alloc().init(Expression::Literal(Literal::RegExp(r.babelify(ctx)))),
                    ),
                    Lit::JSXText(_) => panic!(
                        "illegal conversion: Cannot convert {:?} to ExprOutput",
                        &lit
                    ), // TODO(dwoznicki): is this really illegal?
                    #[cfg(swc_ast_unknown)]
                    _ => panic!("unable to access unknown nodes"),
                }
            }
            Expr::Tpl(t) => {
                ExprOutput::Expr(Box::alloc().init(Expression::TemplateLiteral(t.babelify(ctx))))
            }
            Expr::TaggedTpl(t) => {
                ExprOutput::Expr(Box::alloc().init(Expression::TaggedTemplate(t.babelify(ctx))))
            }
            Expr::Arrow(a) => {
                ExprOutput::Expr(Box::alloc().init(Expression::ArrowFunc(a.babelify(ctx))))
            }
            Expr::Class(c) => {
                ExprOutput::Expr(Box::alloc().init(Expression::Class(c.babelify(ctx))))

View on GitHub (pinned to 5176682b65)

Solutions

  1. Keep JSXText nodes inside JSXElement children where they belong; fix the plugin that relocated them.
  2. Run the react/jsx transform before babelify so all JSX (including JSXText) is lowered to calls and string literals.
  3. When building AST programmatically, use Lit::Str for text values instead of Lit::JSXText.

Example fix

// before: plugin emits JSXText as a standalone expression
Expr::Lit(Lit::JSXText(text))

// after: use a string literal outside JSX
Expr::Lit(Lit::Str(text.into()))
Defensive patterns

Strategy: type-guard

Type guard

// Detect JSXText literals outside JSX text positions before babelify.
fn has_jsxtext_in_expr(program: &Program) -> bool {
    struct Scan(bool);
    impl Visit for Scan {
        fn visit_expr(&mut self, e: &Expr) {
            if matches!(e, Expr::Lit(Lit::JSXText(_))) { self.0 = true; }
            e.visit_children_with(self);
        }
        // JSX element internals are converted by the JSX path; skip them
        fn visit_jsx_element(&mut self, _: &JSXElement) {}
    }
    let mut s = Scan(false);
    program.visit_with(&mut s);
    s.0
}

Prevention

When it happens

Trigger: Babelifying an AST in which Expr::Lit(Lit::JSXText(..)) appears in a general expression position — typically a swc plugin that lifted JSX children into expression slots, or a manually constructed fixture.

Common situations: Writing swc plugins that rearrange JSX children lists; AST test fixtures constructed by hand; round-tripping JSX through custom transforms.

Related errors


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