{"record":{"id":"a72a49709b73689b","repo":"swc-project/swc","slug":"end-of-file-seen-and-there-were-open-elements","errorCode":null,"errorMessage":"End of file seen and there were open elements","messagePattern":"End of file seen and there were open elements","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":6170,"sourceCode":"                    // been popped from the stack.\n                    //\n                    // Clear the list of active formatting elements up to the last marker.\n                    //\n                    // Pop the current template insertion mode off the stack of template insertion\n                    // modes.\n                    //\n                    // Reset the insertion mode appropriately.\n                    //\n                    // Reprocess the token.\n                    Token::Eof => {\n                        if !self.open_elements_stack.contains_template_element() {\n                            self.stopped = true;\n                        } else {\n                            self.update_end_tag_span(\n                                self.open_elements_stack.items.last(),\n                                token_and_info.span,\n                            );\n                            self.errors.push(Error::new(\n                                token_and_info.span,\n                                ErrorKind::EofWithUnclosedElements,\n                            ));\n                            self.open_elements_stack\n                                .pop_until_tag_name_popped(&[\"template\"]);\n                            self.active_formatting_elements.clear_to_last_marker();\n                            self.template_insertion_mode_stack.pop();\n                            self.reset_insertion_mode();\n                            self.process_token(token_and_info, None)?;\n                        }\n                    }\n                }\n            }\n            // The \"after body\" insertion mode\n            InsertionMode::AfterBody => {\n                // When the user agent is to apply the rules for the \"after body\" insertion\n                // mode, the user agent must handle the token as follows:\n                match token {","sourceCodeStart":6152,"sourceCodeEnd":6188,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L6152-L6188","documentation":"The HTML parser hit end-of-input while a <template> element was still on the stack of open elements, inside the 'in template' insertion mode. This is the WHATWG 'eof-with-unclosed-elements' parse error: the source ends before the matching </template>. The parser recovers deterministically (pops the template, clears active formatting elements to the last marker, resets insertion mode, reprocesses EOF), so a Document is still returned; the error only records the unterminated template.","triggerScenarios":"Calling parse_file_as_document or parse_file_as_document_fragment on input that opens <template> without a matching </template> before EOF, e.g. `<body><template><div>row</div>` (no closing tag). The error fires on the EOF token in the 'in template' mode only when open_elements_stack.contains_template_element() is true.","commonSituations":"Server-side templating that conditionally skips the closing tag; minifiers that strip 'redundant' </template>; truncated files (partial upload, cut logs, interrupted stream); hand-written HTML template literals in Rust string concat pipelines.","solutions":["Add the missing </template> for every <template> in the source HTML.","If the HTML is generated, fix the generator/serializer so it always emits the closing template tag, even on early-return/error paths.","Verify the input is not truncated (check file size, checksum, or stream completion) before parsing.","If the input is third-party and the recovered tree is acceptable, filter ErrorKind::EofWithUnclosedElements out of the errors vec returned via parse_file_as_document's errors parameter and treat it as a warning."],"exampleFix":"<!-- before -->\n<template id=\"row\"><div>name</div>\n<script>/* ... */</script>\n\n<!-- after -->\n<template id=\"row\"><div>name</div></template>\n<script>/* ... */</script>","handlingStrategy":"validation","validationCode":"// Pre-check template tag balance before parsing (cheap heuristic).\nfn template_tags_balanced(src: &str) -> bool {\n    let lower = src.to_ascii_lowercase();\n    lower.matches(\"<template\").count() == lower.matches(\"</template\").count()\n}\n\nif !template_tags_balanced(&html_src) {\n    return Err(\"unterminated <template> element\".into());\n}","typeGuard":"use swc_html_parser::error::{Error, ErrorKind};\n\nfn is_eof_with_unclosed_elements(err: &Error) -> bool {\n    matches!(err.kind(), ErrorKind::EofWithUnclosedElements)\n}","tryCatchPattern":"// swc_html_parser never throws recoverable errors; it collects them.\nlet mut errors = Vec::new();\nlet doc = parse_file_as_document(&fm, config, &mut errors)?; // Err = fatal only\nlet fatal: Vec<_> = errors.iter()\n    .filter(|e| !matches!(e.kind(), swc_html_parser::error::ErrorKind::EofWithUnclosedElements))\n    .collect();\nif !fatal.is_empty() { log::warn!(\"html parse errors: {:?}\", fatal); }","preventionTips":["Always emit </template> in generated HTML, including on error/early-return paths.","Validate input completeness (size/checksum) before parsing streamed or downloaded files.","Run an HTML validator on templates in CI to catch unterminated elements.","Treat errors from take_errors()/the errors vec as warnings by default; Err from parse_file_as_document is the only fatal signal."],"tags":["html","parser","swc","template","unclosed-tag","parse-error","eof"],"backgroundTag":"unclosed-html-tag","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}