swc-project/swc · error
illegal conversion: Cannot convert {:?} to ClassBodyEl
Error message
illegal conversion: Cannot convert {:?} to ClassBodyEl What it means
swc_estree_compat converts the SWC AST into a Babel/ESTree-shaped AST (swc_estree_ast). Babel's ClassBody element union has no node for an empty class member, so babelify of ClassMember::Empty — what a stray `;` inside a class body parses to — panics with "illegal conversion: Cannot convert ... to ClassBodyEl" (class.rs:60).
Source
Thrown at crates/swc_estree_compat/src/babelify/class.rs:60
),
id: Default::default(),
mixins: Default::default(),
}
}
}
impl Babelify for ClassMember {
type Output = ClassBodyEl;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
ClassMember::Constructor(c) => ClassBodyEl::Method(c.babelify(ctx)),
ClassMember::Method(m) => ClassBodyEl::Method(m.babelify(ctx)),
ClassMember::PrivateMethod(m) => ClassBodyEl::PrivateMethod(m.babelify(ctx)),
ClassMember::ClassProp(p) => ClassBodyEl::Prop(p.babelify(ctx)),
ClassMember::PrivateProp(p) => ClassBodyEl::PrivateProp(p.babelify(ctx)),
ClassMember::TsIndexSignature(s) => ClassBodyEl::TSIndex(s.babelify(ctx)),
ClassMember::Empty(_) => panic!(
"illegal conversion: Cannot convert {:?} to ClassBodyEl",
&self
),
ClassMember::StaticBlock(s) => ClassBodyEl::StaticBlock(s.babelify(ctx)),
ClassMember::AutoAccessor(..) => todo!("auto accessor"),
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
}
}
}
impl Babelify for ClassProp {
type Output = ClassProperty;
fn babelify(self, ctx: &Context) -> Self::Output {
let computed = Some(self.key.is_computed());
ClassProperty {View on GitHub (pinned to 5176682b65)
Solutions
- Remove stray semicolons from class bodies in the input source.
- Pre-visit the AST and strip ClassMember::Empty nodes before babelify — they are semantically void.
- Patch swc_estree_compat to skip Empty members instead of panicking, and report upstream.
Example fix
// before
class A {
;
method() {}
}
// after
class A {
method() {}
} Defensive patterns
Strategy: type-guard
Validate before calling
// Strip semantically-void empty class members before babelify.
fn drop_empty_class_members(program: &mut Program) {
struct Clean;
impl VisitMut for Clean {
fn visit_mut_class_members(&mut self, n: &mut Vec<ClassMember>) {
n.retain(|m| !matches!(m, ClassMember::Empty(_)));
n.visit_mut_children_with(self);
}
}
program.visit_mut_with(&mut Clean);
} Type guard
fn has_empty_class_member(program: &Program) -> bool {
struct Scan(bool);
impl Visit for Scan {
fn visit_class_member(&mut self, m: &ClassMember) {
if matches!(m, ClassMember::Empty(_)) { self.0 = true; }
m.visit_children_with(self);
}
}
let mut s = Scan(false);
program.visit_with(&mut s);
s.0
} Prevention
- Normalize inputs: strip stray semicolons from class bodies before AST conversion.
- When building conversion pipelines, always run a cleanup pass that drops Empty members.
- Watch for ClassMember::AutoAccessor too — it hits a todo!() in the same match.
When it happens
Trigger: Calling the crate's Babelify conversion (or any tool wrapping swc_estree_compat) on a program containing `class A { ; }` or a trailing semicolon after the last member such as `class A { m() {} ; }`.
Common situations: Machine-generated code with defensive semicolons; formatters leaving `;` after members; converting an already-parsed SWC AST that kept Empty members instead of dropping them.
Related errors
- illegal conversion: Cannot convert {:?} to ExprOutput
- illegal conversion: Cannot convert {:?} to ExprOutput - babe
- illegal conversion: Cannot convert {:?} to Expression - babe
- illegal conversion: Cannot convert {:?} to ObjectKey - babel
- unable to access unknown nodes
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/cd22c80d6584a83b.
Report an issue: GitHub.