swc-project/swc · warning · swc_html_parser::error::Error
Stray doctype
Error message
Stray doctype
What it means
process_token_in_foreign_content (crates/swc_html_parser/src/parser/mod.rs:712) flags a DOCTYPE token that arrives while the insertion point is inside an SVG/MathML subtree. The HTML5 spec says: parse error, ignore the token — nothing is appended to the tree, so this error is purely informational and parsing continues untouched.
Source
Thrown at crates/swc_html_parser/src/parser/mod.rs:712
// Insert the token's character.
//
// Set the frameset-ok flag to "not ok".
Token::Character { .. } => {
self.insert_character(token_and_info)?;
self.frameset_ok = false;
}
// A comment token
//
// Insert a comment.
Token::Comment { .. } => {
self.insert_comment(token_and_info)?;
}
// A DOCTYPE token
// Parse error. Ignore the token.
Token::Doctype { .. } => {
self.errors
.push(Error::new(token_and_info.span, ErrorKind::StrayDoctype));
}
// A start tag whose tag name is one of: "b", "big", "blockquote", "body", "br",
// "center", "code", "dd", "div", "dl", "dt", "em", "embed", "h1", "h2", "h3", "h4",
// "h5", "h6", "head", "hr", "i", "img", "li", "listing", "menu", "meta", "nobr", "ol",
// "p", "pre", "ruby", "s", "small", "span", "strong", "strike", "sub", "sup", "table",
// "tt", "u", "ul", "var"
//
// A start tag whose tag name is "font", if the token has any attributes named "color",
// "face", or "size"
//
// An end tag whose tag name is "br", "p"
//
// Parse error.
//
// While the current node is not a MathML text integration point, an HTML integration
// point, or an element in the HTML namespace, pop elements from the stack of open
// elements.
//View on GitHub (pinned to 5176682b65)
Solutions
- Strip the XML/SVG doctype from the fragment before inlining it into HTML
- Keep exactly one doctype per document, emitted only by the outermost layout
- If you deliberately parse SVG-as-HTML fragments, filter ErrorKind::StrayDoctype from the error list
Example fix
<!-- before --> <svg> <!DOCTYPE svg> <rect width="10" height="10"/> </svg> <!-- after --> <svg> <rect width="10" height="10"/> </svg>
Defensive patterns
Strategy: validation
Validate before calling
fn has_doctype_inside_foreign_content(html: &str) -> bool {
let lower = html.to_ascii_lowercase();
["<svg", "<math"].iter().any(|root| {
lower.match_indices(root).any(|(s, _)| {
let close = format!("</{}", &root[1..]);
let end = lower[s..].find(&close).map(|i| s + i).unwrap_or(lower.len());
lower[s..end].contains("<!doctype")
})
})
} Try / catch
use swc_html_parser::error::ErrorKind;
let mut errors = Vec::new();
let doc = swc_html_parser::parse_file_as_document(&fm, config, &mut errors)?;
// Token is ignored by the spec recovery; document is complete.
for err in &errors {
if matches!(err.kind(), ErrorKind::StrayDoctype) {
log::warn!("doctype ignored inside foreign content");
}
} Prevention
- Inline SVG fragment content without its XML declaration or doctype
- Have the outermost layout own the single document doctype
- Treat StrayDoctype from inlined foreign snippets as a fixture/asset bug
When it happens
Trigger: A `<!DOCTYPE ...>` between `<svg>` (or `<math>`) and its closing tag, e.g. `<svg><!DOCTYPE svg><rect/></svg>` or `<math><mrow><!DOCTYPE math></mrow></math>`. Typically an XML/SVG file that legitimately carries its own doctype gets embedded as a fragment after the HTML parser already entered foreign content.
Common situations: Inlining standalone .svg files into HTML pages, server-side includes stitching doctype-bearing partials, CMS blocks that ship their own document skeleton, naive XHTML-to-HTML string conversion.
Related errors
- HTML start tag "{tag_name}" in a foreign namespace context
- Unexpected null character
- End tag "{end_tag_name}" did not match the name of the curre
- Stray end tag "{tag_name}"
- Non conforming doctype
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/2acbe30df336930b.
Report an issue: GitHub.