swc-project/swc · error

The const_module namespace `{sym}` cannot be used without me

Error message

The const_module namespace `{sym}` cannot be used without member accessor

What it means

`import * as NS from 'mod'` registers NS as a namespace binding for a const module. The transform can only substitute concrete member accesses (NS.member); using NS itself as an expression value (not as the object of a member access) panics with 'The const_module namespace `{sym}` cannot be used without member accessor' because there is no namespace object to materialize.

Source

Thrown at crates/swc_ecma_transforms_optimization/src/const_modules.rs:171

        if self.scope.imported.is_empty() && self.scope.namespace.is_empty() {
            return;
        }

        n.visit_mut_children_with(self);
    }

    fn visit_mut_expr(&mut self, n: &mut Expr) {
        match n {
            Expr::Ident(ref id @ Ident { ref sym, .. }) => {
                let sym_wtf8: Wtf8Atom = sym.clone().into();
                if let Some(value) = self.scope.imported.get(&sym_wtf8) {
                    *n = (**value).clone();
                    return;
                }

                if self.scope.namespace.contains(&id.to_id()) {
                    panic!(
                        "The const_module namespace `{sym}` cannot be used without member accessor"
                    )
                }
            }
            Expr::Member(MemberExpr { obj, prop, .. }) if obj.is_ident() => {
                if let Some(module_name) = obj
                    .as_ident()
                    .filter(|member_obj| self.scope.namespace.contains(&member_obj.to_id()))
                    .map(|member_obj| &member_obj.sym)
                {
                    let imported_name: Wtf8Atom = match prop {
                        MemberProp::Ident(ref id) => id.sym.clone().into(),
                        MemberProp::Computed(ref p) => match &*p.expr {
                            Expr::Lit(Lit::Str(s)) => s.value.clone(),
                            _ => return,
                        },
                        MemberProp::PrivateName(..) => return,
                        #[cfg(swc_ast_unknown)]

View on GitHub (pinned to 5176682b65)

Solutions

  1. Reference concrete members: env.MODE instead of env
  2. Convert the namespace import to named imports for the members actually used
  3. Remove the namespace import if nothing accesses members through it

Example fix

// before
import * as env from '@app/env';
console.log(env); // bare namespace as value -> panic

// after
import * as env from '@app/env';
console.log(env.MODE);
Defensive patterns

Strategy: validation

Validate before calling

// JS: flag bare namespace identifiers used as values
function checkNamespaceUsage(src, globals) {
  const mods = new Set(Object.keys(globals));
  const re = /import\s*\*\s*as\s+([\w$]+)\s+from\s+['"]([^'"]+)['"]/g;
  for (const [, local, mod] of src.matchAll(re)) {
    if (!mods.has(mod)) continue;
    const use = new RegExp(`(?<![.\w$])${local}(?![.\w$])`);
    if (use.test(src.split(/import[^;]+;/).slice(1).join('')))
      throw new Error(`namespace "${local}" used without member accessor`);
  }
}

Prevention

When it happens

Trigger: Code like `import * as env from 'env'; console.log(env);` or passing/broadcasting the namespace identifier anywhere except `NS.member` position; MemberProp::PrivateName accesses also bypass substitution.

Common situations: Debug logging of a namespace, spreading a namespace, generic wrappers receiving the namespace object, refactors that keep a namespace import while new code references the bare identifier.

Related errors


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