swc-project/swc · error

illegal conversion: Cannot convert

Error message

illegal conversion: Cannot convert {:?} to BabelParam

What it means

While converting a function Param, swc_estree_compat maps the inner Pat to a BabelParam. Babel function parameters must be an Identifier or a Pattern (array/object/rest/assignment), but SWC's Pat enum also has Pat::Expr, which wraps an arbitrary expression and has no Babel-parameter equivalent. If a Param's pat is Pat::Expr, the conversion is illegal and the code panics rather than emitting a malformed Babel AST. The SWC parser never produces this shape for valid source code, so it almost always comes from programmatically built or transformed ASTs.

Solutions

  1. Fix the AST producer: parameters must be Pat::Ident/Array/Object/Rest/Assign, never Pat::Expr
  2. If a transform intentionally creates expression-like targets, restructure it to operate on valid parameter patterns before babelify
  3. Add a pre-babelify validation pass over function params and reject/repair Pat::Expr early with a proper error
  4. Wrap babelify in catch_unwind to surface a diagnosable error instead of an abort

Example fix

// before
let param = Param {
    pat: Pat::Expr(Box::new(Expr::Ident(ident.clone()))),
    ..Default::default()
};

// after
let param = Param {
    pat: Pat::Ident(ident.into()),
    ..Default::default()
};
Defensive patterns

Strategy: type-guard

Validate before calling

fn params_babelifiable(program: &Program) -> Result<(), String> {
    for f in functions(program) {
        for p in &f.params {
            if matches!(p.pat, Pat::Expr(_)) {
                return Err(format!("function has expression parameter pattern at {:?}", p.span));
            }
        }
    }
    Ok(())
}

Type guard

fn param_pat_babelifiable(pat: &Pat) -> bool {
    !matches!(pat, Pat::Expr(_) | Pat::Invalid(_))
}

Try / catch

let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| program.babelify(&ctx)))
    .map_err(|_| anyhow::anyhow!("illegal BabelParam conversion: parameter pattern is Pat::Expr"))?;

Prevention

When it happens

Trigger: Babelifying a Program built by custom code that puts Pat::Expr inside a Param (e.g. a transform or macro that rewrites parameters into expressions), or an AST deserialized from another tool that used the invalid shape.

Common situations: Custom swc plugins/transforms that manipulate parameter lists; codemod tooling constructing Params via ..Default::default() and accidentally leaving an Expr; AST fixtures from other ecosystems fed into babelify.

Related errors


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

Appendix: source

Thrown at crates/swc_estree_compat/src/babelify/function.rs:85

                decorators: Some(self.decorators.babelify(ctx)),
                ..a.babelify(ctx)
            })),
            Pat::Rest(r) => BabelParam::Rest(RestElement {
                base: ctx.base(self.span),
                decorators: Some(self.decorators.babelify(ctx)),
                ..r.babelify(ctx)
            }),
            Pat::Object(o) => BabelParam::Pat(Pattern::Object(ObjectPattern {
                base: ctx.base(self.span),
                decorators: Some(self.decorators.babelify(ctx)),
                ..o.babelify(ctx)
            })),
            Pat::Assign(a) => BabelParam::Pat(Pattern::Assignment(AssignmentPattern {
                base: ctx.base(self.span),
                decorators: Some(self.decorators.babelify(ctx)),
                ..a.babelify(ctx)
            })),
            Pat::Expr(_) => panic!(
                "illegal conversion: Cannot convert {:?} to BabelParam",
                &self.pat
            ),
            Pat::Invalid(_) => panic!(
                "illegal conversion: Cannot convert {:?} to BabelParam",
                &self.pat
            ),
            #[cfg(swc_ast_unknown)]
            _ => panic!("unable to access unknown nodes"),
        }
    }
}

impl Babelify for ParamOrTsParamProp {
    type Output = BabelParam;

    fn babelify(self, ctx: &Context) -> Self::Output {
        match self {

View on GitHub (pinned to 5176682b65)