{"record":{"id":"7e0b0ff42827670a","repo":"rust-lang/rust","slug":"extraction-of-the-title-failed","errorCode":null,"errorMessage":"extraction of the title failed","messagePattern":"extraction of the title failed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/tools/rust-analyzer/xtask/src/publish/notes.rs","lineNumber":184,"sourceCode":"            self.output.push('\\n');\n            while let Some(line) = self.iter.next() {\n                let line = line?;\n                if line == LISTING_DELIMITER {\n                    self.write_line(\"```\", level);\n                    return Ok(());\n                } else {\n                    self.write_line(&line, level);\n                }\n            }\n            bail!(\"listing block is not terminated\")\n        }\n        bail!(\"not a listing block\")\n    }\n\n    fn process_block_with_title(&mut self, level: usize) -> anyhow::Result<()> {\n        if let Some(Ok(line)) = self.iter.next() {\n            let title =\n                line.strip_prefix('.').ok_or_else(|| anyhow!(\"extraction of the title failed\"))?;\n\n            let line = self\n                .iter\n                .peek()\n                .ok_or_else(|| anyhow!(\"target block for the title is not found\"))?;\n            let line = line.as_deref().map_err(|e| anyhow!(\"{e}\"))?;\n            if line.starts_with(IMAGE_BLOCK_PREFIX) {\n                return self.process_image_block(Some(title), level);\n            } else if line.starts_with(VIDEO_BLOCK_PREFIX) {\n                return self.process_video_block(Some(title), level);\n            } else {\n                bail!(\"title for that block type is not supported\");\n            }\n        }\n        bail!(\"not a title\")\n    }\n\n    fn process_image_block(&mut self, caption: Option<&str>, level: usize) -> anyhow::Result<()> {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/src/tools/rust-analyzer/xtask/src/publish/notes.rs#L166-L202","documentation":"Thrown by rust-analyzer's AsciiDoc-to-Markdown converter (convert_asciidoc_to_markdown) inside process_block_with_title. After consuming a line that the dispatch loop routed here because it started with '.', the code calls strip_prefix('.') to extract the caption text. Because the function is only entered when the peeked line starts with '.', this branch is effectively unreachable — it would only fire from a bug in the converter's dispatch or a race between peek() and next() on the underlying iterator.","triggerScenarios":"Calling convert_asciidoc_to_markdown on input where the main loop (process, line 39-40) or a list-continuation branch (line 116-117) peeks a line starting with '.', but the subsequently consumed line from self.iter.next() does not actually start with '.'. This can only happen if the AsciiDoc source changes between peek and next or the dispatch logic is modified incorrectly.","commonSituations":"Maintainer editing the AsciiDoc converter dispatch logic and introducing a routing bug; feeding a malformed .adoc file that causes the peek/next invariant to break; a test fixture with a stray '.' line that the converter mishandles.","solutions":["Inspect the input AsciiDoc around the failing line — confirm the line actually starts with '.' and is followed by an image:: or video:: block.","If you are editing the converter, verify that process_block_with_title is only called from branches that already checked line.starts_with('.').","Add a debug assertion or test fixture that reproduces the exact input to isolate the dispatch mismatch.","Report upstream if the error fires without any converter modifications — it indicates a genuine bug in peek/next consistency."],"exampleFix":"// before (buggy dispatch routing a non-'.' line into the title handler):\n} else if line.starts_with('.') {\n    self.process_block_with_title(0)?;\n// after (guard the invariant explicitly):\n} else if line.starts_with('.') {\n    debug_assert!(line.starts_with('.'), \"dispatch invariant broken\");\n    self.process_block_with_title(0)?;","handlingStrategy":"validation","validationCode":"// Before calling convert_asciidoc_to_markdown, validate that the\n// AsciiDoc input doesn't have orphan block-title lines.\nfn validate_no_dangling_titles(input: &str) -> Result<(), String> {\n    let lines: Vec<&str> = input.lines().collect();\n    for (i, line) in lines.iter().enumerate() {\n        if line.starts_with('.') && !line.starts_with(\"..\") {\n            let next = lines.get(i + 1).copied().unwrap_or(\"\");\n            if !next.starts_with(\"image::\") && !next.starts_with(\"video::\") {\n                return Err(format!(\"dangling block title at line {}: '{}'\", i + 1, line));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// Rust: handle the anyhow::Result from convert_asciidoc_to_markdown\nmatch convert_asciidoc_to_markdown(std::io::Cursor::new(&input)) {\n    Ok(markdown) => println!(\"{}\", markdown),\n    Err(e) => eprintln!(\"AsciiDoc conversion failed: {e:#}\"),\n}","preventionTips":["Ensure every '.Caption' line in AsciiDoc release notes is immediately followed by an image:: or video:: block.","Run cargo test -p xtask (test_asciidoc_to_markdown_conversion) before committing AsciiDoc changes.","Validate AsciiDoc source with a lint pass that checks for orphan block titles."],"tags":["rust-analyzer","asciidoc","converter","release-notes","xtask"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}