{"record":{"id":"6d326173d44c08ec","repo":"swc-project/swc","slug":"non-conforming-doctype","errorCode":null,"errorMessage":"Non conforming doctype","messagePattern":"Non conforming doctype","errorType":"exception","errorClass":"swc_html_parser::error::Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":1357,"sourceCode":"                    //\n                    // Then, switch the insertion mode to \"before html\".\n                    Token::Doctype {\n                        name,\n                        public_id,\n                        system_id,\n                        force_quirks,\n                        raw,\n                        ..\n                    } => {\n                        let is_html_name =\n                            matches!(name, Some(name) if name.eq_ignore_ascii_case(\"html\"));\n                        let is_conforming_doctype = is_html_name\n                            && public_id.is_none()\n                            && (system_id.is_none()\n                                || matches!(system_id, Some(system_id) if system_id == \"about:legacy-compat\"));\n\n                        if !is_conforming_doctype {\n                            self.errors.push(Error::new(\n                                token_and_info.span,\n                                ErrorKind::NonConformingDoctype,\n                            ));\n                        }\n\n                        let document_type = Node::new(\n                            Data::DocumentType {\n                                name: name.clone(),\n                                public_id: public_id.clone(),\n                                system_id: system_id.clone(),\n                                raw: raw.clone(),\n                            },\n                            token_and_info.span,\n                        );\n\n                        self.append_node(self.document.as_ref().unwrap(), document_type);\n\n                        if !self.config.iframe_srcdoc","sourceCodeStart":1339,"sourceCodeEnd":1375,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L1339-L1375","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","solutions":["Replace the legacy doctype with `<!DOCTYPE html>`","If the legacy doctype is intentional (archival content), filter ErrorKind::NonConformingDoctype and check the returned document's mode before applying quirks-sensitive processing","For pure AST extraction keep it as-is: the DocumentType node with name/public_id/system_id is still emitted correctly"],"exampleFix":"<!-- before -->\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">...</html>\n\n<!-- after -->\n<!DOCTYPE html>\n<html lang=\"en\">...</html>","handlingStrategy":"validation","validationCode":"fn has_conforming_doctype(html: &str) -> bool {\n    let lower = html.trim_start().to_ascii_lowercase();\n    // Conforming shapes: <!DOCTYPE html> or\n    // <!DOCTYPE html SYSTEM \"about:legacy-compat\"> — never PUBLIC.\n    if !lower.starts_with(\"<!doctype html\") {\n        return false;\n    }\n    let rest = lower[\"<!doctype html\".len()..].trim_start();\n    rest.is_empty()\n        || rest.starts_with('>')\n        || rest.starts_with(\"system \\\"about:legacy-compat\\\"\")\n}","typeGuard":null,"tryCatchPattern":"use swc_html_parser::error::ErrorKind;\n\nlet mut errors = Vec::new();\nlet doc = swc_html_parser::parse_file_as_document(&fm, config, &mut errors)?;\n\nfor err in &errors {\n    if matches!(err.kind(), ErrorKind::NonConformingDoctype) {\n        // Recovery kept the doctype node; mode may be Quirks:\n        log::warn!(\"non-conforming doctype; document mode = {:?}\", doc.mode);\n    }\n}","preventionTips":["Standardize templates on `<!DOCTYPE html>`","Treat any PUBLIC identifier in a doctype as a migration leftover","Assert Document::mode == NoQuirks in layout-sensitive pipelines"],"tags":["html","parser","doctype","quirks-mode","legacy","swc"],"backgroundTag":"invalid-doctype","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"}