{"record":{"id":"795ad2daa10f1548","repo":"swc-project/swc","slug":"end-tag-br","errorCode":null,"errorMessage":"End tag \"br\"","messagePattern":"End tag \"br\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":3739,"sourceCode":"                        self.insert_html_element(token_and_info)?;\n                        self.frameset_ok = false;\n                        self.insertion_mode = InsertionMode::InTable;\n                        maybe_allow_self_closing!(is_self_closing, tag_name);\n                    }\n                    // An end tag whose tag name is \"br\"\n                    //\n                    // Parse error. Drop the attributes from the token, and act as described in the\n                    // next entry; i.e. act as if this was a \"br\" start tag token with no\n                    // attributes, rather than the end tag token that it actually is.\n                    Token::EndTag {\n                        tag_name,\n                        is_self_closing,\n                        ..\n                    } if tag_name == \"br\" => {\n                        let is_self_closing = *is_self_closing;\n\n                        self.errors\n                            .push(Error::new(token_and_info.span, ErrorKind::EndTagBr));\n\n                        self.reconstruct_active_formatting_elements()?;\n                        self.insert_html_element(\n                            &self.create_fake_token_and_info(\"br\", Some(token_and_info.span)),\n                        )?;\n                        self.open_elements_stack.pop();\n\n                        if is_self_closing {\n                            token_and_info.acknowledged = true;\n                        }\n\n                        self.frameset_ok = false;\n                    }\n                    // A start tag whose tag name is one of: \"area\", \"br\", \"embed\", \"img\", \"keygen\",\n                    // \"wbr\"\n                    //\n                    // Reconstruct the active formatting elements, if any.\n                    //","sourceCodeStart":3721,"sourceCodeEnd":3757,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L3721-L3757","documentation":"An end tag `br` (`</br>`) was tokenized (parser/mod.rs:3730-3746). There is no such thing as a `br` end tag — `br` is a void element — so the spec says: parse error, drop the token's attributes, and act as if a `<br>` start tag was seen. The parser records `EndTagBr`, inserts a synthetic `<br>` element from a fake token, immediately pops it, and sets `frameset_ok = false`.","triggerScenarios":"Literal `</br>` anywhere in the input, e.g. `<p>a</br>b</p>`. Often a typo for the XHTML-style self-closing `<br/>`, whose slash ends up on the wrong side.","commonSituations":"Hand-typed XHTML habits (`<br/>` mistyped as `</br>`), find/replace accidents that moved slashes, and machine-generated markup from tools that blindly emit close tags for every element including void ones.","solutions":["Replace `</br>` with `<br>` (HTML) or `<br/>` (XHTML-style), both accepted by the parser","Fix the generator that emits end tags for void elements (`br`, `img`, `input`, `hr`, `meta`, `link`)","Add a lint/grep check for `</br>`, `</img>`, `</input>` in your template pipeline","Note the recovery inserts a real `<br>`, so expect one extra line break in output snapshots"],"exampleFix":"<!-- before -->\n<p>first line</br>second line</p>\n\n<!-- after -->\n<p>first line<br>second line</p>","handlingStrategy":"validation","validationCode":"// Trivial pre-check: reject `</br>` (and other void end tags) before parsing\nfn has_void_end_tags(src: &str) -> bool {\n    [\"br\",\"img\",\"input\",\"hr\",\"meta\",\"link\",\"area\",\"base\",\"col\",\"embed\",\"source\",\"track\",\"wbr\"]\n        .iter()\n        .any(|t| src.contains(&format!(\"</{t}\")))\n}","typeGuard":"fn is_end_tag_br(e: &Error) -> bool {\n    matches!(e.kind, ErrorKind::EndTagBr)\n}","tryCatchPattern":"let doc = parser.parse_document()?;\nlet br_fixups = parser.take_errors().into_iter().filter(is_end_tag_br).count();\nif br_fixups > 0 {\n    // each `</br>` became a real <br> in the tree — verify rendering still fits\n    log::warn!(\"{br_fixups} literal </br> coerced to <br>\");\n}","preventionTips":["Write <br> or <br/>, never </br>","Fix generators that emit end tags for void elements","Add a grep/CI check for `</br>`, `</img>`, `</input>` in template output"],"tags":["html","parser","br","void-elements","typo"],"backgroundTag":"void-element-end-tag","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}