swc-project/swc · error
unable to access unknown nodes
Error message
unable to access unknown nodes
What it means
PatternExt::get_type_ann (crates/swc_typescript/src/fast_dts/util/ast_ext.rs) is the shared helper fast_dts uses to read a type annotation off any binding pattern (unwrapping Pat::Assign to its left side first). Under `--cfg swc_ast_unknown`, a pattern decoded as `Unknown(tag, value)` falls into the catch-all and panics, because there is no annotation field to read on an opaque node. It fires during many passes (parameter checks, declaration transforms), always on deserialized cross-version AST.
Source
Thrown at crates/swc_typescript/src/fast_dts/util/ast_ext.rs:87
fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>);
fn bound_names<F: FnMut(&BindingIdent)>(&self, f: &mut F);
}
impl PatExt for Pat {
fn get_type_ann(&self) -> &Option<Box<TsTypeAnn>> {
let pat = match self {
Pat::Assign(assign_pat) => &assign_pat.left,
_ => self,
};
match pat {
Pat::Ident(binding_ident) => &binding_ident.type_ann,
Pat::Array(array_pat) => &array_pat.type_ann,
Pat::Rest(rest_pat) => &rest_pat.type_ann,
Pat::Object(object_pat) => &object_pat.type_ann,
Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => &None,
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
}
}
fn set_type_ann(&mut self, type_anno: Option<Box<TsTypeAnn>>) {
let pat = match self {
Pat::Assign(assign_pat) => &mut assign_pat.left,
_ => self,
};
match pat {
Pat::Ident(binding_ident) => binding_ident.type_ann = type_anno,
Pat::Array(array_pat) => array_pat.type_ann = type_anno,
Pat::Rest(rest_pat) => rest_pat.type_ann = type_anno,
Pat::Object(object_pat) => object_pat.type_ann = type_anno,
Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) => {}
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
}View on GitHub (pinned to 5176682b65)
Solutions
- Unify on one swc_core version across producer and consumer and rebuild.
- Upgrade swc_typescript/swc_core past the version that introduced the new pattern node.
- Re-parse from source with the same build before FastDts::transform.
- Keep --cfg swc_ast_unknown only in plugin/ABI-stability targets, and rebuild those whenever the producing side changes.
Example fix
// before let ty = pat.get_type_ann(); // panics on Pat::Unknown // after: reject foreign payloads before the transform assert_payload_version_matches(&bytes)?; let ty = pat.get_type_ann();
Defensive patterns
Strategy: type-guard
Validate before calling
// Before any code path that calls get_type_ann on deserialized patterns:
#[cfg(swc_ast_unknown)]
fn safe_get_type_ann(p: &Pat) -> Option<&Option<Box<TsTypeAnn>>> {
if pat_is_known(p) { Some(p.get_type_ann_ref()) } else { None }
} Type guard
#[cfg(swc_ast_unknown)]
fn pat_is_known(p: &Pat) -> bool {
!matches!(p, Pat::Unknown(..))
} Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
let issues = catch_unwind(AssertUnwindSafe(|| dts.transform(&mut program)))
.unwrap_or_else(|p| { tracing::error!("fast_dts rejected AST: {:?}", p.downcast_ref::<&str>()); Vec::new() }); Prevention
- Only pass Programs built by the same compiler instance to fast_dts.
- Guard or reject deserialized patterns before invoking helper traits.
- Align swc crate versions across the workspace.
When it happens
Trigger: Any FastDts pass reads a type annotation from a pattern node whose tag is unknown to this swc_ecma_ast build — e.g. a new binding-pattern variant from a newer swc release inside a deserialized Program.
Common situations: Plugin/host swc version skew; two swc_ecma_ast versions resolved in one binary; persisted AST inputs replayed after upgrading @swc/core or swc_cli.
Related errors
- unable to access unknown nodes
- unable to access unknown nodes
- unable to access unknown nodes
- unable to access unknown nodes
- unable to access unknown nodes
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/5edbc65a7fd2a4e8.
Report an issue: GitHub.