{"record":{"id":"cf23b89b689d28f0","repo":"swc-project/swc","slug":"non-space-character-after-body","errorCode":null,"errorMessage":"Non-space character after body","messagePattern":"Non-space character after body","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":6259,"sourceCode":"                    //\n                    // Stop parsing.\n                    Token::Eof => {\n                        self.update_end_tag_span(\n                            self.open_elements_stack.items.last(),\n                            token_and_info.span,\n                        );\n                        self.stopped = true;\n                    }\n                    // Anything else\n                    //\n                    // Parse error. Switch the insertion mode to \"in body\" and reprocess the token.\n                    _ => {\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!();","sourceCodeStart":6241,"sourceCodeEnd":6277,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L6241-L6277","documentation":"A character token that is not whitespace (not TAB/LF/FF/CR/SPACE) was dispatched in the 'after body' insertion mode, i.e. visible text appeared after </body>. The spec says: parse error, switch to 'in body' and reprocess, so the text still ends up appended inside body. The error (NonSpaceCharacterAfterBody) records the misplaced character with its span.","triggerScenarios":"Any non-whitespace text node after the body close tag, e.g. `<html><body>ok</body>oops`. Only the first reprocessed character token reports; the follow-up tokens are then handled in 'in body' mode without error.","commonSituations":"Analytics/tracking snippets or banner text appended after </body> by reverse proxies; string-concatenation page builders that lose ordering; build steps that inject content at 'end of file' rather than 'end of body'.","solutions":["Move the stray text before </body> in the source.","Fix the generator/injector so it inserts content at the end of body, not after the closing tag.","If the markup is third-party and the recovered tree (text inside body) is acceptable, filter ErrorKind::NonSpaceCharacterAfterBody from the errors vec."],"exampleFix":"<!-- before -->\n<body>content</body>\ntracker-pixel-text\n</html>\n\n<!-- after -->\n<body>content\ntracker-pixel-text\n</body>\n</html>","handlingStrategy":"validation","validationCode":"// Detect non-whitespace content after the last </body>.\nfn has_text_after(src: &str, close: &str) -> bool {\n    let lower = src.to_ascii_lowercase();\n    lower.rfind(close)\n        .map(|i| lower[i + close.len()..].chars().any(|c| !c.is_ascii_whitespace()))\n        .unwrap_or(false)\n}\n\nif has_text_after(&html_src, \"</body>\") { /* fix injector before parsing */ }","typeGuard":"use swc_html_parser::error::{Error, ErrorKind};\n\nfn is_non_space_after_body(err: &Error) -> bool {\n    matches!(err.kind(), ErrorKind::NonSpaceCharacterAfterBody)\n}","tryCatchPattern":"let mut errors = Vec::new();\nlet doc = parse_file_as_document(&fm, config, &mut errors)?;\n// Recovery moves the text into body; decide whether that is acceptable.\nif errors.iter().any(is_non_space_after_body) {\n    log::warn!(\"text after </body> was relocated into body\");\n}","preventionTips":["Inject content before </body>, never after it.","In CI, assert nothing but whitespace/comments follows the last </body>.","Prefer DOM-level manipulation over string concat when appending nodes."],"tags":["html","parser","swc","text-node","after-body","parse-error"],"backgroundTag":"content-after-body","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"}