{"record":{"id":"26af141c1e3d0c93","repo":"Hmbown/CodeWhale","slug":"snippet-regex-pattern-is-valid","errorCode":null,"errorMessage":"snippet regex pattern is valid","messagePattern":"snippet regex pattern is valid","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/web/scrape.rs","lineNumber":43,"sourceCode":"static SNIPPET_RE: OnceLock<Regex> = OnceLock::new();\nstatic TAG_RE: OnceLock<Regex> = OnceLock::new();\nstatic BING_RESULT_RE: OnceLock<Regex> = OnceLock::new();\nstatic BING_TITLE_RE: OnceLock<Regex> = OnceLock::new();\nstatic BING_SNIPPET_RE: OnceLock<Regex> = OnceLock::new();\n\nfn get_title_re() -> &'static Regex {\n    TITLE_RE.get_or_init(|| {\n        Regex::new(r#\"<a[^>]*class=\\\"result__a\\\"[^>]*href=\\\"([^\\\"]+)\\\"[^>]*>(.*?)</a>\"#)\n            .expect(\"title regex pattern is valid\")\n    })\n}\n\nfn get_snippet_re() -> &'static Regex {\n    SNIPPET_RE.get_or_init(|| {\n        Regex::new(\n            r#\"<a[^>]*class=\\\"result__snippet\\\"[^>]*>(.*?)</a>|<div[^>]*class=\\\"result__snippet\\\"[^>]*>(.*?)</div>\"#,\n        )\n        .expect(\"snippet regex pattern is valid\")\n    })\n}\n\nfn get_tag_re() -> &'static Regex {\n    TAG_RE.get_or_init(|| Regex::new(r\"<[^>]+>\").expect(\"tag regex pattern is valid\"))\n}\n\nfn get_bing_result_re() -> &'static Regex {\n    BING_RESULT_RE.get_or_init(|| {\n        Regex::new(r#\"(?is)<li[^>]*class=\\\"[^\\\"]*\\bb_algo\\b[^\\\"]*\\\"[^>]*>(.*?)</li>\"#)\n            .expect(\"bing result regex pattern is valid\")\n    })\n}\n\nfn get_bing_title_re() -> &'static Regex {\n    BING_TITLE_RE.get_or_init(|| {\n        Regex::new(r#\"(?is)<h2[^>]*>.*?<a[^>]*href=\\\"([^\\\"]+)\\\"[^>]*>(.*?)</a>\"#)\n            .expect(\"bing title regex pattern is valid\")","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tools/web/scrape.rs#L25-L61","documentation":"Panic compiling the DuckDuckGo snippet pattern — a two-alternative regex matching `<a class=\"result__snippet\">` or `<div class=\"result__snippet\">`, with the match taken from capture group 1 or 2. Like the other scrape getters it is a hardcoded literal behind `SNIPPET_RE.get_or_init`, so the expect fires only when an edit made the literal syntactically invalid (the alternation and nested quotes are the easy parts to break).","triggerScenarios":"Editing the snippet literal and leaving an unbalanced parenthesis, a broken `|` alternation, or a malformed escape; the first `parse_duckduckgo_results` call after that build panics in `get_snippet_re`'s `get_or_init`.","commonSituations":"Loosening the snippet selector for a DDG markup change; pasting a pattern written for a regex dialect with different escape rules (e.g. escaping `/` or using `\\/` unnecessarily inside a raw string).","solutions":["Fix the literal and validate it compiles in the Rust regex flavor before committing.","Force-initialize the getter in a unit test so CI catches syntax breaks.","Run the scrape test target after any pattern edit."],"exampleFix":"// before\nRegex::new(\n    r#\"<a[^>]*class=\\\"result__snippet\\\"[^>]*>(.*?)</a>|<div[^>]*class=\\\"result__snippet\\\"[^>]*>(.*?)</div>\"#,\n).expect(\"snippet regex pattern is valid\")\n\n// after: validate the edited pattern in isolation first\n#[test]\nfn snippet_pattern_edits_compile() {\n    let re = get_snippet_re();\n    assert_eq!(re.captures_len() - 1, 2); // two capture groups preserved\n}","handlingStrategy":"validation","validationCode":"#[test]\nfn snippet_pattern_compiles_with_two_groups() {\n    let re = get_snippet_re();\n    assert_eq!(re.captures_len() - 1, 2);\n}","typeGuard":null,"tryCatchPattern":"let snippets = std::panic::catch_unwind(|| collect_snippets(&html))\n    .unwrap_or_default();","preventionTips":["Validate edited patterns against the Rust regex flavor before committing.","Pin capture-group counts in tests so edits that compile but change extraction are caught too."],"tags":["rust","regex","duckduckgo","html-scraping","panic","expect"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}