swc-project/swc · warning · swc_html_parser::error::Error
NoElementToCloseButEndTagSeen
NoElementToCloseButEndTagSeen
Error message
No "{tag_name}" element in scope but a "{tag_name}" end tag seen What it means
Inside the adoption agency algorithm (used for formatting end tags like `</b>`, `</a>`, `</em>`), step 4 locates the formatting element from the list of active formatting elements on the stack of open elements. If it is not on the stack at all (crates/swc_html_parser/src/parser/mod.rs:7314), the parser reports `NoElementToCloseButEndTagSeen`, removes the element from the active formatting list, and ignores the token.
Source
Thrown at crates/swc_html_parser/src/parser/mod.rs:7314
});
if formatting_element.is_none() {
self.any_other_end_tag_for_in_body_insertion_mode(token_and_info);
return Ok(());
}
let formatting_element = formatting_element.unwrap();
// 4.
let formatting_element_stack_index = self
.open_elements_stack
.items
.iter()
.rposition(|n| is_same_node(n, &formatting_element.1));
if formatting_element_stack_index.is_none() {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::NoElementToCloseButEndTagSeen(subject),
));
self.active_formatting_elements
.remove(&formatting_element.1);
return Ok(());
}
// 5.
if formatting_element_stack_index.is_some()
&& !self
.open_elements_stack
.has_node_in_scope(&formatting_element.1)
{
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::NoElementToCloseButEndTagSeen(subject),View on GitHub (pinned to 5176682b65)
Solutions
- Fix the source so formatting elements are closed in LIFO order where practical
- Re-serialize the document through a tolerant parser (parse then print) to normalize the lists
- If untrusted input, cap nesting/formatting depth before parsing
- Treat as recoverable: the parser drops the token and continues; verify the final tree
Example fix
<!-- before (mis-nested formatting) --> <b><i>one</b>two</i> <!-- after --> <b><i>one</i></b><i>two</i>
Defensive patterns
Strategy: validation
Validate before calling
// Normalize before parsing: run the tolerant parser once and re-serialize
let normalized = {
let mut parser = Parser::new(lexer);
let doc = parser.parse_document()?;
print_document(&doc)? // re-serialization resets active-formatting state
}; Try / catch
for err in parser.take_errors() {
if matches!(err.kind, ErrorKind::NoElementToCloseButEndTagSeen(_)) {
// end tag ignored; formatting entry removed from active list
}
} Prevention
- Close formatting tags in LIFO order in generated markup
- Round-trip untrusted/mangled HTML through parse+print before deep processing
- Cap formatting-tag nesting depth in sanitizers to avoid pathological adoption-agency inputs
When it happens
Trigger: A formatting element still referenced by the active formatting elements list but no longer present on the open elements stack — typically after table/text insertion-mode handling popped it — followed by its end tag. Example shape: `<b><li>x</b>` variants where earlier recovery left the lists inconsistent, then `</b>` arrives.
Common situations: Deeply mis-nested formatting tags produced by WYSIWYG editors; malformed HTML round-tripped through tolerant tools; inputs intentionally crafted to stress the adoption agency (fuzz corpora, legacy CMS output).
Related errors
- EndTagViolatesNestingRules
- Start tag "{tag_name}" seen but an element of the same type
- No cell to close
- "select" start tag where end tag expected
- "{tag_name}" start tag with "select" open
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/94ce0ccd9e455921.
Report an issue: GitHub.