swc-project/swc · error
empty expression container
Error message
empty expression container
What it means
During JSX-to-function conversion, process_attr_value (jsx/mod.rs:539) must turn every JSX attribute value into an expression. A JSXExprContainer whose expr is JSXEmptyExpr — an attribute written `attr={}` — has no value to emit, so the transform panics with "empty expression container". The SWC parser normally rejects empty expression containers, so in practice this fires on programmatically built, plugin-modified, or error-recovered ASTs rather than plain source text.
Source
Thrown at crates/swc_ecma_transforms_react/src/jsx/mod.rs:545
.as_arg()
}
fn jsx_dev_self_arg(&self) -> ExprOrSpread {
if self.self_ctx.can_add_self() {
ThisExpr { span: DUMMY_SP }.as_arg()
} else {
Expr::undefined(DUMMY_SP).as_arg()
}
}
/// Process JSX attribute value, handling JSXElements and JSXFragments
fn process_attr_value(&mut self, value: Option<JSXAttrValue>) -> Box<Expr> {
match value {
Some(JSXAttrValue::JSXElement(el)) => Box::new(self.jsx_elem_to_expr(*el)),
Some(JSXAttrValue::JSXFragment(frag)) => Box::new(self.jsx_frag_to_expr(frag)),
Some(JSXAttrValue::JSXExprContainer(container)) => match container.expr {
JSXExpr::Expr(e) => e,
JSXExpr::JSXEmptyExpr(_) => panic!("empty expression container"),
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
},
Some(v) => jsx_attr_value_to_expr(v).expect("empty expression container?"),
None => true.into(),
}
}
fn inject_runtime<T, F>(&mut self, body: &mut Vec<T>, inject: F)
where
T: StmtLike,
// Fn(Vec<(local, imported)>, src, body)
F: Fn(Vec<(Ident, IdentName)>, &str, &mut Vec<T>),
{
if self.runtime == Runtime::Automatic {
if let Some(local) = self.import_create_element.take() {
inject(
vec![(local, quote_ident!("createElement"))],View on GitHub (pinned to 5176682b65)
Solutions
- Find the `{}` attribute in the offending element and give it a real expression, or remove the attribute entirely.
- If a plugin produced it, fix the plugin to drop the whole JSXAttr when clearing its value.
- Run a pre-flight visitor that reports JSXExprContainer-with-JSXEmptyExpr before invoking the react transform.
Example fix
// before (AST shape reaching the transform)
<Foo bar={} />
// after
<Foo bar={"" />}
// or simply: <Foo /> Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight scan: reject JSX attributes with empty expression containers.
#[derive(Default)]
struct EmptyJsxAttr { bad: Vec<Span> }
impl Visit for EmptyJsxAttr {
fn visit_jsx_attr(&mut self, attr: &JSXAttr) {
if let Some(JSXAttrValue::JSXExprContainer(c)) = &attr.value {
if matches!(c.expr, JSXExpr::JSXEmptyExpr(_)) {
self.bad.push(attr.span);
}
}
attr.visit_children_with(self);
}
} Prevention
- If a codemod clears an attribute value, delete the whole JSXAttr, not just the expression.
- Treat parser diagnostics as fatal so empty containers are caught at parse time.
- Lint for `={}` in JSX sources in CI.
When it happens
Trigger: Feeding the react JSX pass an AST in which some JSXAttr.value is JSXExprContainer { expr: JSXEmptyExpr } — i.e. `<Foo bar={} />` produced by a lenient parser, an AST builder, or a swc plugin/codemod that emptied the container but kept the attribute.
Common situations: Codemods or plugins that delete an attribute's expression while leaving the container; hand-written AST fixtures; parsing with error recovery enabled and ignoring diagnostics.
Related errors
- failed to parse jsx option {}: '{}' is not an expression
- Duplicate __source is found
- Duplicate __self is found
- attr_to_prop(JSXEmptyExpr)
- illegal conversion: Cannot convert {:?} to ExprOutput
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/87397648357db2f2.
Report an issue: GitHub.