{"record":{"id":"0014fbb4d9176df8","repo":"rust-lang/mdBook","slug":"internal-error-expected-empty-tag-stack-path-0014fb","errorCode":null,"errorMessage":"internal error: expected empty tag stack.\n\n path: `{}`\nnode={node:?}","messagePattern":"internal error: expected empty tag stack\\.\n\n path: `(.+?)`\nnode=(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/mdbook-html/src/html/tree.rs","lineNumber":829,"sourceCode":"                Node::Fragment => {}\n                Node::Element(el) => {\n                    if el.was_raw {\n                        warn!(\n                            \"unclosed HTML tag `<{}>` found in `{}`\",\n                            el.name.local,\n                            self.options.path.display()\n                        );\n                    } else {\n                        panic!(\n                            \"internal error: expected empty tag stack.\\n\n                             path: `{}`\\n\\\n                             element={el:?}\",\n                            self.options.path.display()\n                        );\n                    }\n                }\n                node => {\n                    panic!(\n                        \"internal error: expected empty tag stack.\\n\n                         path: `{}`\\n\\\n                         node={node:?}\",\n                        self.options.path.display()\n                    );\n                }\n            }\n        }\n    }\n\n    /// Appends a new footnote reference.\n    fn footnote_reference(&mut self, name: CowStr<'event>) {\n        let len = self.footnote_numbers.len() + 1;\n        let (n, count) = self\n            .footnote_numbers\n            .entry(name.clone())\n            .or_insert((len, 0));\n        *count += 1;","sourceCodeStart":811,"sourceCodeEnd":847,"githubUrl":"https://github.com/rust-lang/mdBook/blob/dc21064fc21d955a0e1f67e65e336883c3e5260b/crates/mdbook-html/src/html/tree.rs#L811-L847","documentation":"The sibling case of the finish_stack drain: when the leftover item on the tag_stack is not an Element but some other node kind, mdbook-html cannot even attribute it to an unclosed HTML tag, so it panics immediately with the node debug dump. This signals deep inconsistency between the events processed and the tree structure built.","triggerScenarios":"process_events finishes a document with a non-element node (e.g. a Text/Html pseudo-entry) still on the tag stack — typically caused by a preprocessor emitting events that mutate the stack shape (append without matching pop) or an internal bug in event handling for a specific node type.","commonSituations":"Custom preprocessors that emit events out of contract (e.g. raw tree manipulation or misordered Start/End pairs), parser upgrades changing event kinds so tree.rs pushes/pops differently, or corrupted/generated markdown with interleaved constructs.","solutions":["Disable preprocessors one by one to find which one produces events breaking the tree invariant.","Fix the preprocessor to emit strictly balanced, well-ordered pulldown-cmark events.","Check for version mismatches between pulldown-cmark used by mdbook-html and your toolchain; rebuild consistently.","Minimize the failing chapter and file a bug with the node dump from the panic message."],"exampleFix":"// before (preprocessor) — emits End without Start\nevents.push(Event::End(TagEnd::HtmlBlock));\n\n// after — always pair Start/End\nevents.push(Event::Start(Tag::HtmlBlock));\nevents.push(Event::Html(text));\nevents.push(Event::End(TagEnd::HtmlBlock));","handlingStrategy":"validation","validationCode":"// ensure preprocessor output events are strictly balanced Start/End pairs\nlet mut depth = 0i32;\nfor ev in &processed {\n    match ev {\n        Event::Start(_) => depth += 1,\n        Event::End(_) => { depth -= 1; if depth < 0 { bail!(\"End without Start in preprocessor output\"); } }\n        _ => {}\n    }\n}\nif depth != 0 { bail!(\"{} Start events without matching End\", depth); }","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(|| render_book(&book))\n    .map_err(|_| anyhow!(\"tag stack invariant violated: bisect preprocessors to find the one emitting malformed events\"))?;","preventionTips":["Test preprocessors on a minimal book before enabling book-wide.","Never emit End events without a matching Start in preprocessors.","Upgrade mdbook/pulldown-cmark together, not independently."],"tags":["panic","internal-error","tag-stack","preprocessor"],"backgroundTag":"unbalanced-tag-stack","analyzedSha":"dc21064fc21d955a0e1f67e65e336883c3e5260b","analyzedAt":"2026-09-01T10:15:12.134Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}