{"record":{"id":"a6fa87e37ea15f9f","repo":"swc-project/swc","slug":"non-space-characters-found-without-seeing-a-doctyp","errorCode":null,"errorMessage":"Non-space characters found without seeing a doctype first, expected \"<!DOCTYPE html>\"","messagePattern":"Non-space characters found without seeing a doctype first, expected \"<!DOCTYPE html>\"","errorType":"exception","errorClass":"swc_html_parser::error::Error","httpStatus":null,"severity":"warning","filePath":"crates/swc_html_parser/src/parser/mod.rs","lineNumber":1426,"sourceCode":"                    // In any case, switch the insertion mode to \"before html\", then reprocess the\n                    // token.\n                    _ => {\n                        if !self.config.iframe_srcdoc {\n                            match &token {\n                                Token::StartTag { .. } => {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::StartTagWithoutDoctype,\n                                    ));\n                                }\n                                Token::EndTag { .. } => {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::EndTagSeenWithoutDoctype,\n                                    ));\n                                }\n                                Token::Character { .. } => {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::NonSpaceCharacterWithoutDoctype,\n                                    ));\n                                }\n                                Token::Eof => {\n                                    self.errors.push(Error::new(\n                                        token_and_info.span,\n                                        ErrorKind::EofWithoutDoctype,\n                                    ));\n                                }\n                                _ => {\n                                    unreachable!();\n                                }\n                            }\n\n                            self.set_document_mode(DocumentMode::Quirks);\n                        }\n","sourceCodeStart":1408,"sourceCodeEnd":1444,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_html_parser/src/parser/mod.rs#L1408-L1444","documentation":"Initial insertion mode, 'anything else' branch (crates/swc_html_parser/src/parser/mod.rs:1426): the first token is a character token that is not ASCII whitespace, no doctype preceded it, and iframe_srcdoc is false. Parse error; quirks mode is set and the character is reprocessed downstream. Leading whitespace is ignored by the initial mode and does NOT trigger this.","triggerScenarios":"Input whose first non-whitespace, non-comment content is text, e.g. `hello world` or `404: page not found` parsed as HTML with no doctype.","commonSituations":"Plain-text files fed to the HTML parser by content-sniffing code, error pages, template fragments starting with prose, log output wrapped in HTML parsing.","solutions":["Prepend `<!DOCTYPE html>` and proper markup if the input is meant to be HTML","Check the content type before parsing — plain text should not go through the HTML parser","Set ParserConfig { iframe_srcdoc: true, .. } for fragment-like input"],"exampleFix":"// before\nlet fm = cm.new_source_file(file.into(), \"hello world, no markup\".into());\nlet doc = parse_file_as_document(&fm, config, &mut errors)?; // NonSpaceCharacterWithoutDoctype\n\n// after\nlet fm = cm.new_source_file(file.into(), \"<!DOCTYPE html>hello world\".into());\nlet doc = parse_file_as_document(&fm, config, &mut errors)?;","handlingStrategy":"validation","validationCode":"fn starts_with_nonspace_text(html: &str) -> bool {\n    let mut rest = html.trim_start();\n    while let Some(t) = rest.strip_prefix(\"<!--\") {\n        match t.find(\"-->\") {\n            Some(i) => rest = t[i + 3..].trim_start(),\n            None => return false,\n        }\n    }\n    let lower = rest.to_ascii_lowercase();\n    !lower.is_empty() && !lower.starts_with(\"<!doctype\") && !rest.starts_with('<')\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::NonSpaceCharacterWithoutDoctype) {\n        log::warn!(\"bare leading text; input may not be HTML at all\");\n    }\n}","preventionTips":["Content-sniff before parsing: text/plain content should skip the HTML parser","Wrap prose fragments in minimal `<div>...</div>` plus doctype when a Document is required","Set iframe_srcdoc = true for srcdoc parsing"],"tags":["html","parser","doctype","text-node","quirks-mode","swc"],"backgroundTag":"missing-doctype","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}