{"record":{"id":"2b0b0f6616015dd3","repo":"swc-project/swc","slug":"unable-to-access-unknown-nodes-2b0b0f","errorCode":null,"errorMessage":"unable to access unknown nodes","messagePattern":"unable to access unknown nodes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_typescript/src/fast_dts/types.rs","lineNumber":37,"sourceCode":"    FastDts,\n};\nuse crate::fast_dts::util::ast_ext::PropNameExit;\n\nimpl FastDts {\n    pub(crate) fn transform_expr_to_ts_type(&mut self, expr: &Expr) -> Option<Box<TsType>> {\n        match expr {\n            Expr::Ident(ident) if ident.sym == \"undefined\" => {\n                Some(ts_keyword_type(TsKeywordTypeKind::TsUndefinedKeyword))\n            }\n            Expr::Lit(lit) => match lit {\n                Lit::Str(string) => Some(ts_lit_type(TsLit::Str(string.clone()))),\n                Lit::Bool(b) => Some(ts_lit_type(TsLit::Bool(*b))),\n                Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)),\n                Lit::Num(number) => Some(ts_lit_type(TsLit::Number(number.clone()))),\n                Lit::BigInt(big_int) => Some(ts_lit_type(TsLit::BigInt(big_int.clone()))),\n                Lit::Regex(_) | Lit::JSXText(_) => None,\n                #[cfg(swc_ast_unknown)]\n                _ => panic!(\"unable to access unknown nodes\"),\n            },\n            Expr::Tpl(tpl) => self\n                .tpl_to_string(tpl)\n                .map(|string| ts_lit_type(TsLit::Str(string))),\n            Expr::Unary(unary) if Self::can_infer_unary_expr(unary) => {\n                let mut expr = self.transform_expr_to_ts_type(&unary.arg)?;\n                if unary.op == UnaryOp::Minus {\n                    match &mut expr.as_mut_ts_lit_type()?.lit {\n                        TsLit::Number(number) => {\n                            number.value = -number.value;\n                            number.raw = None;\n                        }\n                        TsLit::BigInt(big_int) => {\n                            *big_int.value = -*big_int.value.clone();\n                            big_int.raw = None;\n                        }\n                        _ => {}\n                    }","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_typescript/src/fast_dts/types.rs#L19-L55","documentation":"transform_expr_to_ts_type (crates/swc_typescript/src/fast_dts/types.rs:24) converts a constant expression to a literal TS type (string/bool/null/number/bigint literals) for const initializers, enum members and property defaults. In `--cfg swc_ast_unknown` builds, a literal kind this build does not recognize decodes to `Unknown(tag, value)` and the inner Lit match panics, because no TsLit can be fabricated from an opaque node. Like all such panics, it appears only when deserialized AST from a different swc_ecma_ast version reaches fast_dts.","triggerScenarios":"FastDts converts an expression (e.g. `export const s = <newLitKind>` or an enum member initializer) whose literal node was deserialized as an unknown Lit variant from a payload written by a newer swc version.","commonSituations":"Version skew between a swc wasm plugin (built with swc_ast_unknown) and its @swc/core host; AST round-trip fixtures or caches spanning an upgrade; CI runs that intentionally compile with RUSTFLAGS=\"--cfg swc_ast_unknown\".","solutions":["Align producer and consumer on one swc_core/swc_ecma_ast version and rebuild everything together.","Upgrade swc_typescript/swc_core to a version that knows the new literal node.","Prefer same-process parsing of source text over accepting serialized ASTs before FastDts::transform.","Version-gate serialized AST inputs and re-parse on mismatch."],"exampleFix":"// before\nlet mut program: Program = bincode::deserialize(&cached)?;\ndts.transform(&mut program);\n\n// after: cache keyed by swc version, re-parse on mismatch\nlet mut program = match load_cache(cache_key_of(swc_ecma_ast_version())) {\n    Some(p) => p,\n    None => parse_program(&cm, &src)?, // same-build parser\n};\ndts.transform(&mut program);","handlingStrategy":"type-guard","validationCode":"// Check literals in const/enum initializers before transform:\n#[cfg(swc_ast_unknown)]\nfn init_lits_known(decls: &[VarDeclarator]) -> bool {\n    decls.iter().all(|d| match &d.init {\n        Some(e) => !matches!(e.as_ref(), Expr::Lit(l) if matches!(l, Lit::Unknown(..))),\n        None => true,\n    })\n}","typeGuard":"#[cfg(swc_ast_unknown)]\nfn lit_is_known(l: &Lit) -> bool {\n    !matches!(l, Lit::Unknown(..))\n}","tryCatchPattern":"use std::panic::{catch_unwind, AssertUnwindSafe};\nmatch catch_unwind(AssertUnwindSafe(|| dts.transform(&mut program))) {\n    Ok(issues) => issues,\n    Err(_) => { program = parse_program(&cm, &src)?; dts.transform(&mut program) }\n}","preventionTips":["Keep serializer and consumer on the same swc_ecma_ast version.","Version serialized AST caches and invalidate them on upgrade.","Prefer same-process parse + transform over decode + transform."],"tags":["swc","fast-dts","unknown-ast-node","version-mismatch","panic","literal-type","const"],"backgroundTag":"ast-version-mismatch","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}