{"record":{"id":"18464f52cf59d528","repo":"swc-project/swc","slug":"saw-an-end-tag-after-body-had-been-closed","errorCode":null,"errorMessage":"Saw an end tag after \"body\" had been closed","messagePattern":"Saw an end tag after \"body\" had been closed","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":6271,"sourceCode":"                    _ => {\n                        match token {\n                            // Doctype handled above\n                            // Comment handled above\n                            // EOF handled above\n                            Token::Character { .. } => {\n                                self.errors.push(Error::new(\n                                    token_and_info.span,\n                                    ErrorKind::NonSpaceCharacterAfterBody,\n                                ));\n                            }\n                            Token::StartTag { tag_name, .. } => {\n                                self.errors.push(Error::new(\n                                    token_and_info.span,\n                                    ErrorKind::StrayStartTag(tag_name.clone()),\n                                ));\n                            }\n                            Token::EndTag { .. } => {\n                                self.errors.push(Error::new(\n                                    token_and_info.span,\n                                    ErrorKind::EndTagAfterBody,\n                                ));\n                            }\n                            _ => {\n                                unreachable!();\n                            }\n                        }\n\n                        self.insertion_mode = InsertionMode::InBody;\n                        self.process_token(token_and_info, None)?;\n                    }\n                }\n            }\n            // The \"in frameset\" insertion mode\n            InsertionMode::InFrameset => {\n                // When the user agent is to apply the rules for the \"in frameset\" insertion\n                // mode, the user agent must handle the token as follows:","sourceCodeStart":6253,"sourceCodeEnd":6289,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L6253-L6289","documentation":"An end tag other than </html> appeared in the 'after body' insertion mode. This is the spec's parse error reported as ErrorKind::EndTagAfterBody; the parser switches to 'in body' and reprocesses the token, so normal end-tag handling applies afterwards.","triggerScenarios":"A stray closing tag after </body>, e.g. `</body></div>` or `</body></p>`. The 'anything else' arm of AfterBody mode matches Token::EndTag and pushes EndTagAfterBody.","commonSituations":"Templates whose macro/layout closes a wrapper element outside the body region; unbalanced markup where an outer container was closed early; copy-paste of page fragments that carry their own closing tags.","solutions":["Remove or relocate the stray closing tag so every end tag sits inside body.","Re-balance the markup: ensure each open tag inside <body> is closed before </body>.","Add an HTML validation step (validator.nu or html5ever-based linter) to CI for template sources.","If tolerated, filter ErrorKind::EndTagAfterBody from the errors vec; the parser recovers."],"exampleFix":"<!-- before -->\n<body><div><p>x</div></p></body></div></html>\n\n<!-- after -->\n<body><div><p>x</p></div></body></html>","handlingStrategy":"validation","validationCode":"// Any non-html end tag after the last </body> is a stray close.\nfn has_end_tag_after_body(src: &str) -> bool {\n    let lower = src.to_ascii_lowercase();\n    match lower.rfind(\"</body>\") {\n        None => false,\n        Some(i) => lower[i..].matches(\"</\").count() > 1, // </body> itself + more\n    }\n}","typeGuard":"use swc_html_parser::error::{Error, ErrorKind};\n\nfn is_end_tag_after_body(err: &Error) -> bool {\n    matches!(err.kind(), ErrorKind::EndTagAfterBody)\n}","tryCatchPattern":"let mut errors = Vec::new();\nlet doc = parse_file_as_document(&fm, config, &mut errors)?;\nif errors.iter().any(is_end_tag_after_body) {\n    log::warn!(\"end tag seen after body close; reprocessed in body\");\n}","preventionTips":["Close every element opened inside body before </body>.","Validate template balance with an HTML linter in CI.","Watch for copy-pasted fragments that carry their own closing tags."],"tags":["html","parser","swc","end-tag","after-body","parse-error"],"backgroundTag":"stray-html-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"}