{"record":{"id":"87397648357db2f2","repo":"swc-project/swc","slug":"empty-expression-container","errorCode":null,"errorMessage":"empty expression container","messagePattern":"empty expression container","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_ecma_transforms_react/src/jsx/mod.rs","lineNumber":545,"sourceCode":"        .as_arg()\n    }\n\n    fn jsx_dev_self_arg(&self) -> ExprOrSpread {\n        if self.self_ctx.can_add_self() {\n            ThisExpr { span: DUMMY_SP }.as_arg()\n        } else {\n            Expr::undefined(DUMMY_SP).as_arg()\n        }\n    }\n\n    /// Process JSX attribute value, handling JSXElements and JSXFragments\n    fn process_attr_value(&mut self, value: Option<JSXAttrValue>) -> Box<Expr> {\n        match value {\n            Some(JSXAttrValue::JSXElement(el)) => Box::new(self.jsx_elem_to_expr(*el)),\n            Some(JSXAttrValue::JSXFragment(frag)) => Box::new(self.jsx_frag_to_expr(frag)),\n            Some(JSXAttrValue::JSXExprContainer(container)) => match container.expr {\n                JSXExpr::Expr(e) => e,\n                JSXExpr::JSXEmptyExpr(_) => panic!(\"empty expression container\"),\n                #[cfg(swc_ast_unknown)]\n                _ => panic!(\"unable to access unknown nodes\"),\n            },\n            Some(v) => jsx_attr_value_to_expr(v).expect(\"empty expression container?\"),\n            None => true.into(),\n        }\n    }\n\n    fn inject_runtime<T, F>(&mut self, body: &mut Vec<T>, inject: F)\n    where\n        T: StmtLike,\n        // Fn(Vec<(local, imported)>, src, body)\n        F: Fn(Vec<(Ident, IdentName)>, &str, &mut Vec<T>),\n    {\n        if self.runtime == Runtime::Automatic {\n            if let Some(local) = self.import_create_element.take() {\n                inject(\n                    vec![(local, quote_ident!(\"createElement\"))],","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_ecma_transforms_react/src/jsx/mod.rs#L527-L563","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (AST shape reaching the transform)\n<Foo bar={} />\n\n// after\n<Foo bar={\"\" />}\n// or simply: <Foo />","handlingStrategy":"validation","validationCode":"// Pre-flight scan: reject JSX attributes with empty expression containers.\n#[derive(Default)]\nstruct EmptyJsxAttr { bad: Vec<Span> }\nimpl Visit for EmptyJsxAttr {\n    fn visit_jsx_attr(&mut self, attr: &JSXAttr) {\n        if let Some(JSXAttrValue::JSXExprContainer(c)) = &attr.value {\n            if matches!(c.expr, JSXExpr::JSXEmptyExpr(_)) {\n                self.bad.push(attr.span);\n            }\n        }\n        attr.visit_children_with(self);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["swc","jsx","react","ast","panic"],"backgroundTag":"empty-jsx-expression-container","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}