{"record":{"id":"c1c531a4a39369c3","repo":"Y2Z/monolith","slug":"unable-to-serialize-dom-into-buffer","errorCode":null,"errorMessage":"unable to serialize DOM into buffer","messagePattern":"unable to serialize DOM into buffer","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/html.rs","lineNumber":49,"sourceCode":"    Favicon,\n    Preload,\n    Stylesheet,\n    Manifest,\n}\n\npub struct SrcSetItem<'a> {\n    pub path: &'a str,\n    pub descriptor: &'a str, // Width or pixel density descriptor\n}\n\npub fn add_favicon(document: &Handle, favicon_data_url: String) -> RcDom {\n    let mut buf: Vec<u8> = Vec::new();\n    serialize(\n        &mut buf,\n        &SerializableHandle::from(document.clone()),\n        SerializeOpts::default(),\n    )\n    .expect(\"unable to serialize DOM into buffer\");\n\n    let dom = html_to_dom(&buf, \"utf-8\".to_string());\n    for head in find_nodes(&dom.document, vec![\"html\", \"head\"]).iter() {\n        let favicon_node = create_element(\n            &dom,\n            QualName::new(None, ns!(), LocalName::from(\"link\")),\n            vec![\n                Attribute {\n                    name: QualName::new(None, ns!(), LocalName::from(\"rel\")),\n                    value: format_tendril!(\"icon\"),\n                },\n                Attribute {\n                    name: QualName::new(None, ns!(), LocalName::from(\"href\")),\n                    value: format_tendril!(\"{}\", favicon_data_url),\n                },\n            ],\n        );\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/Y2Z/monolith/blob/a6fc8d009514b2ea271dda2539f19a1f479ebfab/src/html.rs#L31-L67","documentation":"`add_favicon` serializes the document DOM back to bytes with html5ever's `serialize` and panics via `.expect(\"unable to serialize DOM into buffer\")` when serialization returns `Err`. This happens when the DOM tree is malformed for the serializer (corrupt tree produced by parsing bad input or by earlier manipulation). The panic aborts document processing rather than skipping the favicon injection.","triggerScenarios":"Calling `create_monolithic_document_from_data` (which calls `add_favicon`) on input whose parsed DOM fails html5ever serialization — typically corrupt, truncated, or binary data parsed as HTML, or an error writing into the in-memory `Vec<u8>` buffer.","commonSituations":"Pointing monolith at non-HTML responses (images, PDFs, gzipped bodies not decompressed, error pages) that parse into a broken tree; HTML with exotic encodings or unencodable characters; server returning truncated HTML.","solutions":["Validate the input is real HTML (correct Content-Type, decompressed if Content-Encoding: gzip) before calling `create_monolithic_document_from_data`.","Re-parse the document from the original bytes with `html_to_dom` instead of serializing a mutated DOM.","Serialize a valid `SerializableHandle` (whole document) rather than a detached/odd node.","Catch the panic with `catch_unwind` if you must tolerate bad inputs, and/or file an issue with the failing HTML upstream."],"exampleFix":"// before\nserialize(\n    &mut buf,\n    &SerializableHandle::from(document.clone()),\n    SerializeOpts::default(),\n)\n.expect(\"unable to serialize DOM into buffer\");\n// after\nif serialize(\n    &mut buf,\n    &SerializableHandle::from(document.clone()),\n    SerializeOpts::default(),\n)\n.is_err()\n{\n    eprintln!(\"skipping favicon: DOM not serializable\");\n    return;\n}","handlingStrategy":"try-catch","validationCode":"fn looks_like_html(bytes: &[u8], content_type: &str) -> bool {\n    content_type.starts_with(\"text/html\")\n        && !bytes.starts_with(&[0x1f, 0x8b]) // not gzip\n        && std::str::from_utf8(bytes)\n            .map(|s| {\n                let l = s.to_ascii_lowercase();\n                l.contains(\"<html\") || l.contains(\"<!doctype\")\n            })\n            .unwrap_or(false)\n}","typeGuard":"fn is_valid_html_input(data: &[u8]) -> bool {\n    std::str::from_utf8(data)\n        .map(|s| {\n            let l = s.trim_start().to_ascii_lowercase();\n            l.starts_with(\"<!doctype html\") || l.contains(\"<html\")\n        })\n        .unwrap_or(false)\n}","tryCatchPattern":"let result = std::panic::catch_unwind(|| {\n    create_monolithic_document_from_data(&data, &url)\n});\nmatch result {\n    Ok(doc) => use_document(doc),\n    Err(_) => eprintln!(\"monolith panicked serializing DOM (favicon step); skipping document\"),\n}","preventionTips":["Only feed text/html responses into monolith; skip binary/gzip/error pages.","Decompress Content-Encoding bodies before parsing.","Validate the body is UTF-8 HTML before processing.","Keep monolith and html5ever versions in sync and tested against your target pages."],"tags":["rust","panic","html5ever","serialization","dom"],"backgroundTag":"dom-serialization-failed","analyzedSha":"a6fc8d009514b2ea271dda2539f19a1f479ebfab","analyzedAt":"2026-09-05T20:13:04.517Z","contentChangedAt":"2026-09-05T20:13:04.517Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}