swc-project/swc · error
Non-computed member expression with property other than iden
Error message
Non-computed member expression with property other than ident is invalid
What it means
During bundler import analysis, member expressions on imported bindings (`ns.prop`) are recorded as usages with the exported context applied to the property identifier. A non-computed member must have MemberProp::Ident; this arm fires when the property is a PrivateName (`ns.#field`) — private-name access on an import namespace binding, which the bundler cannot rewrite and which is invalid in that position in ECMAScript.
Source
Thrown at crates/swc_bundler/src/bundler/import/mod.rs:318
});
let import = match import {
Some(v) => v,
None => return,
};
let src_atom = import.src.value.to_atom_lossy();
let mark = self.ctxt_for(src_atom.as_ref());
let exported_ctxt = match mark {
None => return,
Some(ctxts) => ctxts.1,
};
let prop = match &e.prop {
MemberProp::Ident(i) => {
let mut i = Ident::from(i.clone());
i.ctxt = exported_ctxt;
i
}
_ => unreachable!(
"Non-computed member expression with property other than ident is invalid"
),
};
self.usages
.entry(obj.to_id())
.or_default()
.push(prop.to_id());
}
}
}
fn try_deglob(&mut self, e: &mut Expr) {
let me = match e {
Expr::Member(e) => e,
_ => return,
};
if me.prop.is_computed() {View on GitHub (pinned to 5176682b65)
Solutions
- Fix the input source: private fields can only be accessed inside the class that declares them; use a normal property
- If you build AST programmatically, validate MemberExpr nodes (reject MemberProp::PrivateName on imported bindings) before handing modules to the bundler
- If valid parsed input reaches this, report it to swc with the exact snippet
Example fix
// before import * as foo from './foo'; console.log(foo.#secret); // after import * as foo from './foo'; console.log(foo.secret);
Defensive patterns
Strategy: validation
Validate before calling
// Reject private-name member access on imported namespaces before bundling
let private_member = regex::Regex::new(r"\.#[A-Za-z_$]").unwrap();
for (path, src) in &sources {
if private_member.is_match(src) {
return Err(format!("{}: `.#field` outside a class body is invalid", path));
}
} Type guard
// If building AST programmatically, walk it first
fn has_invalid_private_member(m: &swc_ecma_ast::Module) -> bool {
struct V(bool);
impl Visit for V {
fn visit_member_expr(&mut self, e: &MemberExpr) {
if matches!(e.prop, MemberProp::PrivateName(_)) { self.0 = true; }
e.visit_children_with(self);
}
}
let mut v = V(false);
m.visit_with(&mut v);
v.0
} Try / catch
if let Err(p) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| bundler.bundle(&entries))) {
if panic_message(&p).contains("Non-computed member expression") {
// surface a user-facing error about invalid `.#prop` usage instead of crashing
} else { std::panic::resume_unwind(p); }
} Prevention
- Never generate `.#prop` member expressions outside class bodies
- Validate hand-built AST with a visitor before passing it to the bundler
- Lint sources for `.#` sequences in bundler inputs
When it happens
Trigger: Source like `import * as foo from './foo'; foo.#bar` (invalid JS but producible by hand-built or machine-generated AST) fed to swc_bundler; transforms/macros that clone private-name member expressions onto imported bindings.
Common situations: Code generation tools or macro output that emit `.#prop` outside class bodies; hand-constructed swc_ecma_ast trees that skip validation; sloppy-mode scripts with unusual syntax accepted by lenient parsers.
Related errors
- Unknown statement type: ${(stmt as any).type
- Method visitTsType not implemented.
- empty expression container
- Modules reexported with `export * as foo from './foo'` shoul
- Plan does not contain bundle kind for {:?}
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/34c93846b6fb1698.
Report an issue: GitHub.