swc-project/swc · warning · swc_html_parser::error::Error

Non conforming doctype

Error message

Non conforming doctype

What it means

The DOCTYPE token handled in the initial insertion mode (crates/swc_html_parser/src/parser/mod.rs:1357) is not the one conforming form: the name must equal 'html' ASCII-case-insensitively, there must be no public identifier, and the system identifier must be absent or exactly "about:legacy-compat". The parser still appends the DocumentType node to the document and computes quirks/limited-quirks mode from the public/system id tables, but records NonConformingDoctype.

Source

Thrown at crates/swc_html_parser/src/parser/mod.rs:1357

                    //
                    // Then, switch the insertion mode to "before html".
                    Token::Doctype {
                        name,
                        public_id,
                        system_id,
                        force_quirks,
                        raw,
                        ..
                    } => {
                        let is_html_name =
                            matches!(name, Some(name) if name.eq_ignore_ascii_case("html"));
                        let is_conforming_doctype = is_html_name
                            && public_id.is_none()
                            && (system_id.is_none()
                                || matches!(system_id, Some(system_id) if system_id == "about:legacy-compat"));

                        if !is_conforming_doctype {
                            self.errors.push(Error::new(
                                token_and_info.span,
                                ErrorKind::NonConformingDoctype,
                            ));
                        }

                        let document_type = Node::new(
                            Data::DocumentType {
                                name: name.clone(),
                                public_id: public_id.clone(),
                                system_id: system_id.clone(),
                                raw: raw.clone(),
                            },
                            token_and_info.span,
                        );

                        self.append_node(self.document.as_ref().unwrap(), document_type);

                        if !self.config.iframe_srcdoc

View on GitHub (pinned to 5176682b65)

Solutions

  1. Replace the legacy doctype with `<!DOCTYPE html>`
  2. If the legacy doctype is intentional (archival content), filter ErrorKind::NonConformingDoctype and check the returned document's mode before applying quirks-sensitive processing
  3. For pure AST extraction keep it as-is: the DocumentType node with name/public_id/system_id is still emitted correctly

Example fix

<!-- before -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">...</html>

<!-- after -->
<!DOCTYPE html>
<html lang="en">...</html>
Defensive patterns

Strategy: validation

Validate before calling

fn has_conforming_doctype(html: &str) -> bool {
    let lower = html.trim_start().to_ascii_lowercase();
    // Conforming shapes: <!DOCTYPE html> or
    // <!DOCTYPE html SYSTEM "about:legacy-compat"> — never PUBLIC.
    if !lower.starts_with("<!doctype html") {
        return false;
    }
    let rest = lower["<!doctype html".len()..].trim_start();
    rest.is_empty()
        || rest.starts_with('>')
        || rest.starts_with("system \"about:legacy-compat\"")
}

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)?;

for err in &errors {
    if matches!(err.kind(), ErrorKind::NonConformingDoctype) {
        // Recovery kept the doctype node; mode may be Quirks:
        log::warn!("non-conforming doctype; document mode = {:?}", doc.mode);
    }
}

Prevention

When it happens

Trigger: Any doctype with a PUBLIC identifier — XHTML 1.0 (`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`), HTML 4.01 flavors — or a SYSTEM identifier other than "about:legacy-compat".

Common situations: Legacy pages, frameworks defaulting to XHTML doctypes, migrated JSP/PHP/ASP templates, fixtures copied from old W3C examples. Watch the side effect: these doctypes often flip Document.mode to Quirks/LimitedQuirks, which changes how downstream layout or serialization treats the tree.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/6d326173d44c08ec. Report an issue: GitHub.