{"record":{"id":"30f266153faea7dc","repo":"swc-project/swc","slug":"module-string-names-unimplemented-30f266","errorCode":null,"errorMessage":"module string names unimplemented","messagePattern":"module string names unimplemented","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_bundler/src/bundler/import/mod.rs","lineNumber":372,"sourceCode":"            _ => return,\n        };\n        prop.ctxt = self.imported_idents.get(&obj.to_id()).copied().unwrap();\n\n        *e = prop.into();\n    }\n}\n\nimpl<L, R> VisitMut for ImportHandler<'_, '_, L, R>\nwhere\n    L: Load,\n    R: Resolve,\n{\n    noop_visit_mut_type!(fail);\n\n    fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {\n        let orig = match &s.orig {\n            ModuleExportName::Ident(ident) => ident,\n            ModuleExportName::Str(..) => unimplemented!(\"module string names unimplemented\"),\n            #[cfg(swc_ast_unknown)]\n            _ => panic!(\"unable to access unknown nodes\"),\n        };\n\n        self.add_forced_ns_for(orig.to_id());\n\n        match &mut s.exported {\n            Some(ModuleExportName::Ident(exported)) => {\n                // PR 3139 (https://github.com/swc-project/swc/pull/3139) removes the syntax context from any named exports from other sources.\n                exported.ctxt = self.module_ctxt;\n            }\n            Some(ModuleExportName::Str(..)) => unimplemented!(\"module string names unimplemented\"),\n            #[cfg(swc_ast_unknown)]\n            Some(_) => panic!(\"unable to access unknown nodes\"),\n            None => {\n                let exported = Ident::new(orig.sym.clone(), orig.span, self.module_ctxt);\n                s.exported = Some(ModuleExportName::Ident(exported));\n            }","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/swc-project/swc/blob/d7d74346665e36e692aa07e13d4ee3ee692ee35c/crates/swc_bundler/src/bundler/import/mod.rs#L354-L390","documentation":"The import-handling visitor in swc_bundler (import/mod.rs:372) rewrites re-export specifiers like `export { a as b } from './mod'`. When the original name is a string (`export { \"a\" as b } from './mod'`, ModuleExportName::Str for s.orig), it hits unimplemented!() because add_forced_ns_for needs a real Ident/Id. The panic aborts bundling.","triggerScenarios":"A module re-exports a string-named binding: `export { \"foo-bar\" as fooBar } from './dep';`. The visitor visit_mut_export_named_specifier matches Str on s.orig and panics.","commonSituations":"Barrel files re-exporting generated exports with non-identifier names; dependencies whose ESM entry uses string re-export names; pipelines that transpile each file fine and only fail when the SWC bundler joins modules.","solutions":["Change the re-export to reference an identifier: `export { \"foo-bar\" as fooBar } from './dep'` -> rename the export inside './dep' to `fooBar` and re-export normally.","If you don't control the dep, patch it (patch-package) or wrap it in a shim module that assigns the string-named import to an identifier before re-exporting.","Pre-transform the graph with a custom SWC pass converting Str origs to Idents.","Externalize the module from the bundle."],"exampleFix":"// before\nexport { \"foo-bar\" as fooBar } from './dep';\n\n// after (shim.ts)\nimport { \"foo-bar\" as tmp } from './dep';\nexport const fooBar = tmp;","handlingStrategy":"validation","validationCode":"// Screen re-exports (export ... from) for string origs before bundling\nuse swc_ecma_ast::*;\nfor i in &m.body {\n    if let ModuleItem::ModuleDecl(ModuleDecl::ExportNamedDecl(d)) = i {\n        if d.src.is_some() {\n            for s in &d.specifiers {\n                if let ExportSpecifier::Named(n) = s {\n                    if matches!(n.orig, ModuleExportName::Str(_)) {\n                        anyhow::bail!(\"string orig in re-export from {}\", d.src.as_ref().unwrap().value);\n                    }\n                }\n            }\n        }\n    }\n}","typeGuard":"fn reexport_has_string_orig(m: &swc_ecma_ast::Module) -> bool {\n    use swc_ecma_ast::*;\n    m.body.iter().any(|i| matches!(i,\n        ModuleItem::ModuleDecl(ModuleDecl::ExportNamedDecl(d))\n            if d.src.is_some() && d.specifiers.iter().any(|s| matches!(s,\n                ExportSpecifier::Named(n) if matches!(n.orig, ModuleExportName::Str(_))))))\n}","tryCatchPattern":"match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| bundler.bundle(part)?)) {\n    Ok(v) => v,\n    Err(p) if format!(\"{:?}\", &p).contains(\"module string names\") =>\n        Err(anyhow::anyhow!(\"string-named re-export; rename at the exporting module\")),\n    Err(p) => std::panic::resume_unwind(p),\n}","preventionTips":["Keep re-export statements in your own code identifier-only; check them in code review.","When vendoring dependencies, normalize their re-export statements once.","Run a bundle smoke test per dependency version bump.","Screen modules in the Load impl so re-exports from dependencies are caught too."],"tags":["swc","bundler","esm","es2022","module-string-names","panic","re-export","import-handler"],"backgroundTag":null,"analyzedSha":"d7d74346665e36e692aa07e13d4ee3ee692ee35c","analyzedAt":"2026-08-16T12:41:13.160Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}