swc-project/swc · error
unable to access unknown nodes
Error message
unable to access unknown nodes
What it means
swc_ecma_ast can be built with `--cfg=swc_ast_unknown`, which adds `Unknown` variants to AST enums for forward compatibility with plugin hosts (see crates/swc_plugin_backend_tests/tests/fixture/.cargo/config.toml). Under that cfg, every exhaustive match in swc_estree_compat carries an `_ => panic!("unable to access unknown nodes")` arm (expr.rs:175 for Expr); it fires when the AST actually contains an Unknown node, i.e. the AST came from a different swc_ecma_ast version than the converter was compiled against.
Source
Thrown at crates/swc_estree_compat/src/babelify/expr.rs:175
),
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",
&self
),
Expr::OptChain(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
Expr::Invalid(_) => panic!(
"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent",
&self
),
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
}
}
}
impl From<ExprOutput> for Expression {
fn from(o: ExprOutput) -> Self {
match o {
ExprOutput::Expr(expr) => *expr,
ExprOutput::Private(_) => panic!(
"illegal conversion: Cannot convert {:?} to Expression - babel has no equivalent",
&o
),
}
}
}
impl From<ExprOutput> for BinaryExprLeft {
fn from(o: ExprOutput) -> Self {View on GitHub (pinned to 5176682b65)
Solutions
- For normal (non-plugin) builds, drop `--cfg=swc_ast_unknown` from RUSTFLAGS so the arm is compiled out.
- Align swc_ecma_ast / swc_core versions between the AST producer and swc_estree_compat so no Unknown nodes exist.
- If you must run under the cfg, reject Unknown nodes at your boundary before calling babelify.
Example fix
# before: .cargo/config.toml [build] rustflags = ["--cfg=swc_ast_unknown"] # after [build] rustflags = []
Defensive patterns
Strategy: validation
Validate before calling
// When running under --cfg=swc_ast_unknown, screen deserialized ASTs first.
#[cfg(swc_ast_unknown)]
fn has_unknown_expr(program: &Program) -> bool {
struct Scan(bool);
impl Visit for Scan {
fn visit_expr(&mut self, e: &Expr) {
if matches!(e, Expr::Unknown(_)) { self.0 = true; }
e.visit_children_with(self);
}
}
let mut s = Scan(false);
program.visit_with(&mut s);
s.0
} Prevention
- Do not set `--cfg=swc_ast_unknown` in normal builds; reserve it for plugin-runtime builds.
- Keep swc_ecma_ast/swc_core versions identical between AST producers and swc_estree_compat.
- Automate a version-alignment check in CI for plugin projects.
When it happens
Trigger: Building swc crates with rustflags = ["--cfg=swc_ast_unknown"] and babelifying an AST containing Unknown variants — typically deserialized from a plugin/host process whose swc_ecma_ast/swc_core version differs from swc_estree_compat's.
Common situations: SWC plugin development where plugin and host crate versions drift; CI configurations enabling the cfg globally; mixing published swc crate versions in one dependency graph.
Related errors
- illegal conversion: Cannot convert {:?} to ClassBodyEl
- 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
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/48ceaa6cec6e6d81.
Report an issue: GitHub.