swc-project/swc · error
illegal conversion: Cannot convert {:?} to ExprOutput - babe
Error message
illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent What it means
Expr::JSXMember — the `Foo.Bar` in an element name like `<Foo.Bar />` — has no standalone Babel Expression equivalent (Babel's JSXMemberExpression is only legal inside JSX names), so the generic expression conversion panics at expr.rs:146. Normally JSXMember lives inside JSXElementName and is handled by the JSX element babelify path; hitting this arm means a JSXMember node was lifted into a plain expression slot.
Source
Thrown at crates/swc_estree_compat/src/babelify/expr.rs:146
}
Expr::JSXElement(e) => {
ExprOutput::Expr(Box::alloc().init(Expression::JSXElement(e.babelify(ctx))))
}
Expr::JSXFragment(f) => {
ExprOutput::Expr(Box::alloc().init(Expression::JSXFragment(f.babelify(ctx))))
}
Expr::TsTypeAssertion(a) => {
ExprOutput::Expr(Box::alloc().init(Expression::TSTypeAssertion(a.babelify(ctx))))
}
Expr::TsNonNull(n) => {
ExprOutput::Expr(Box::alloc().init(Expression::TSNonNull(n.babelify(ctx))))
}
Expr::TsAs(a) => ExprOutput::Expr(Box::alloc().init(Expression::TSAs(a.babelify(ctx)))),
Expr::TsInstantiation(..) => unimplemented!("Babel doesn't support this right now."),
Expr::PrivateName(p) => ExprOutput::Private(p.babelify(ctx)),
// TODO(dwoznicki): how does babel handle these?
Expr::JSXMember(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
Expr::JSXNamespacedName(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
Expr::JSXEmpty(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
Expr::TsConstAssertion(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
Expr::TsSatisfies(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&selfView on GitHub (pinned to 5176682b65)
Solutions
- Keep member element names inside JSXElement; let the JSX babelify path convert them.
- Lower JSX first with the react transform so babelify never sees JSXMember.
- If a name must be an expression, rewrite it to a plain Expr::Member (Ident.member) before babelify.
Example fix
// before: lifted into an expression slot
Expr::JSXMember(jsx_member_foo_bar)
// after: plain member expression
member_expr(ident!("Foo"), ident_name!("Bar")) Defensive patterns
Strategy: type-guard
Type guard
fn has_jsxmember_in_expr(program: &Program) -> bool {
struct Scan(bool);
impl Visit for Scan {
fn visit_expr(&mut self, e: &Expr) {
if matches!(e, Expr::JSXMember(_)) { self.0 = true; }
e.visit_children_with(self);
}
fn visit_jsx_element(&mut self, _: &JSXElement) {}
}
let mut s = Scan(false);
program.visit_with(&mut s);
s.0
} Prevention
- Lower JSX before estree conversion; JSXMember only converts inside the JSX element path.
- When extracting element names in plugins, emit plain Expr::Member, not Expr::JSXMember.
- Cover member-named elements (`<Foo.Bar/>`) in your conversion test fixtures.
When it happens
Trigger: Babelifying an AST where a JSXMember appears as a general Expr — e.g. a plugin/codemod extracted an element name into an expression container or argument, or an AST fixture built with JSXMember in the wrong slot.
Common situations: swc plugins that rewrite JSX element names (e.g. renaming library prefixes); AST round-tripping tools; hand-written fixtures.
Related errors
- illegal conversion: Cannot convert {:?} to ExprOutput
- illegal conversion: Cannot convert {:?} to ClassBodyEl
- illegal conversion: Cannot convert {:?} to Expression - babe
- illegal conversion: Cannot convert {:?} to ObjectKey - babel
- failed to parse jsx option {}: '{}' is not an expression
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/4124d1ad31fdd6d0.
Report an issue: GitHub.