swc-project/swc · error

unable to access unknown nodes

Error message

unable to access unknown nodes

What it means

This is the entry point FastDts::transform (crates/swc_typescript/src/fast_dts/mod.rs:87): it dispatches on the Program, handling Program::Module and Program::Script. In builds compiled with `--cfg swc_ast_unknown`, swc_ecma_ast's decoder can yield an `Unknown(tag, value)` top-level program when the serialized payload's node tag is not recognized by this build, and the catch-all arm panics with "unable to access unknown nodes". Hitting this particular site means even the root node is foreign — the whole payload was written by a different swc_ecma_ast version.

Source

Thrown at crates/swc_typescript/src/fast_dts/mod.rs:88

    pub fn mark_diagnostic<T: Into<Cow<'static, str>>>(&mut self, message: T, range: Span) {
        self.diagnostics.push(DtsIssue {
            message: message.into(),
            range: SourceRange {
                filename: self.filename.clone(),
                span: range,
            },
        })
    }
}

impl FastDts {
    pub fn transform(&mut self, program: &mut Program) -> Vec<DtsIssue> {
        match program {
            Program::Module(module) => self.transform_module_body(&mut module.body, false),
            Program::Script(script) => self.transform_script(script),
            #[cfg(swc_ast_unknown)]
            _ => panic!("unable to access unknown nodes"),
        }
        take(&mut self.diagnostics)
    }

    fn transform_module_body(
        &mut self,
        items: &mut Vec<ModuleItem>,
        in_global_or_lit_module: bool,
    ) {
        // 1. Analyze usage
        self.used_refs.extend(TypeUsageAnalyzer::analyze(
            items,
            self.internal_annotations.as_ref(),
        ));

        // 2. Transform.
        Self::remove_function_overloads_in_module(items);
        self.transform_module_items(items);

View on GitHub (pinned to 5176682b65)

Solutions

  1. Pin and align the single swc_core version used by both the AST producer and the swc_typescript consumer; verify with `cargo tree -i swc_ecma_ast` that only one version resolves.
  2. Upgrade the consumer (swc_typescript/swc_core/@swc/core) to at least the producer's version so the root Program decodes concretely.
  3. Re-parse from source with the same build's swc_ecma_parser instead of deserializing foreign payloads.
  4. Version-stamp serialized ASTs and reject/fall back to re-parse when the stamp does not match the current swc_ecma_ast version.

Example fix

// before: blindly decode any payload into a Program
let program: Program = deserialize(bytes)?;
let issues = dts.transform(&mut program);

// after: gate on the payload's swc version before decoding
let header = read_swc_version(&bytes);
if header != current_ast_version() {
    return Err(format!("AST payload from {header} cannot feed this build"));
}
let mut program: Program = deserialize(bytes)?;
let issues = dts.transform(&mut program);
Defensive patterns

Strategy: validation

Validate before calling

// Gate the deserialization boundary, not the transform:
fn try_decode_program(bytes: &[u8]) -> Result<Program, String> {
    let producer = read_embedded_swc_version(bytes)?;
    if producer != compiled_ast_version() {
        return Err(format!("AST payload from swc {producer} cannot feed this build"));
    }
    decode(bytes).map_err(|e| e.to_string())
}
// compiled_ast_version(): record env!("CARGO_PKG_VERSION") of swc_ecma_ast at build time.

Type guard

#[cfg(swc_ast_unknown)]
fn program_is_known(p: &Program) -> bool {
    !matches!(p, Program::Unknown(..))
}

Try / catch

use std::panic::{catch_unwind, AssertUnwindSafe};
let issues = catch_unwind(AssertUnwindSafe(|| dts.transform(&mut program)))
    .map_err(|p| p.downcast_ref::<&str>().map(|s| s.to_string()).unwrap_or_default())?;

Prevention

When it happens

Trigger: FastDts::transform is called on a Program deserialized (serde/cbor/plugin boundary) from a payload whose root program representation differs from what this build of swc_ecma_ast defines — e.g. a payload from a newer or incompatible swc release.

Common situations: Swc wasm plugins receive serialized AST from the host (the plugin fixture .cargo/config.toml sets `--cfg=swc_ast_unknown` exactly for this); CI matrix jobs compile with RUSTFLAGS="--cfg swc_ast_unknown" and check cross-version behavior; custom tooling that persists Programs to disk and reloads them after an upgrade.

Related errors


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