{"record":{"id":"79df58cd550d5d35","repo":"swc-project/swc","slug":"nonspacecharacterintrailer","errorCode":"NonSpaceCharacterInTrailer","errorMessage":"Non-space character in page trailer","messagePattern":"Non-space character in page trailer","errorType":"validation","errorClass":"swc_html_parser::error::Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":6591,"sourceCode":"                    Token::StartTag { tag_name, .. } if tag_name == \"html\" => {\n                        self.process_token_using_rules(token_and_info, InsertionMode::InBody)?;\n                    }\n                    // An end-of-file token\n                    //\n                    // Stop parsing.\n                    Token::Eof => {\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::NonSpaceCharacterInTrailer,\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 { tag_name, .. } => {\n                                self.errors.push(Error::new(\n                                    token_and_info.span,\n                                    ErrorKind::StrayEndTag(tag_name.clone()),\n                                ));\n                            }\n                            _ => {\n                                unreachable!();","sourceCodeStart":6573,"sourceCodeEnd":6609,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L6573-L6609","documentation":"A non-whitespace character token arrived in the 'after after body' insertion mode, i.e. visible text after </html>. This is the spec's 'non-space-character-in-trailer' parse error: the parser switches back to 'in body' and reprocesses, so the text is appended to body despite appearing after the document end. NonSpaceCharacterInTrailer records the misplaced character.","triggerScenarios":"Text after the html close tag, e.g. `<html><body>x</body></html>trailing`. The 'anything else' arm of AfterAfterBody mode (crates/swc_html_parser/src/parser/mod.rs:6593) pushes the error, sets insertion_mode = InBody, and reprocesses the token.","commonSituations":"Tracking pixels and text nodes appended after </html> by append-to-file tooling; naive template concatenation; whitespace-trimming build steps that expose stray characters after the document close.","solutions":["Move the stray text before </body> in the source.","Fix the builder/injector to insert content inside body rather than after </html>.","If third-party and the recovered placement (text inside body) is fine, filter ErrorKind::NonSpaceCharacterInTrailer from the errors vec."],"exampleFix":"<!-- before -->\n<html><body>main</body></html>\nappended text\n\n<!-- after -->\n<html><body>main\nappended text\n</body></html>","handlingStrategy":"validation","validationCode":"// Non-whitespace after the last </html> is page-trailer content.\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// has_text_after(&html, \"</html>\")","typeGuard":"use swc_html_parser::error::{Error, ErrorKind};\n\nfn is_non_space_in_trailer(err: &Error) -> bool {\n    matches!(err.kind(), ErrorKind::NonSpaceCharacterInTrailer)\n}","tryCatchPattern":"let mut errors = Vec::new();\nlet doc = parse_file_as_document(&fm, config, &mut errors)?;\nif errors.iter().any(is_non_space_in_trailer) {\n    log::warn!(\"text after </html> was relocated into body\");\n}","preventionTips":["Files must end at </html> (plus trailing whitespace/newline).","Fix append-to-file tooling that writes text after the document close.","Add a CI assertion that the rendered page matches `(?s).*</html>\\s*$`."],"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"}