Hmbown/CodeWhale · error

snippet regex pattern is valid

Error message

snippet regex pattern is valid

What it means

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).

Solutions

  1. Fix the literal and validate it compiles in the Rust regex flavor before committing.
  2. Force-initialize the getter in a unit test so CI catches syntax breaks.
  3. Run the scrape test target after any pattern edit.

Example fix

// before
Regex::new(
    r#"<a[^>]*class=\"result__snippet\"[^>]*>(.*?)</a>|<div[^>]*class=\"result__snippet\"[^>]*>(.*?)</div>"#,
).expect("snippet regex pattern is valid")

// after: validate the edited pattern in isolation first
#[test]
fn snippet_pattern_edits_compile() {
    let re = get_snippet_re();
    assert_eq!(re.captures_len() - 1, 2); // two capture groups preserved
}
Defensive patterns

Strategy: validation

Validate before calling

#[test]
fn snippet_pattern_compiles_with_two_groups() {
    let re = get_snippet_re();
    assert_eq!(re.captures_len() - 1, 2);
}

Try / catch

let snippets = std::panic::catch_unwind(|| collect_snippets(&html))
    .unwrap_or_default();

Prevention

When it happens

Trigger: 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`.

Common situations: 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).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/26af141c1e3d0c93. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/web/scrape.rs:43

static SNIPPET_RE: OnceLock<Regex> = OnceLock::new();
static TAG_RE: OnceLock<Regex> = OnceLock::new();
static BING_RESULT_RE: OnceLock<Regex> = OnceLock::new();
static BING_TITLE_RE: OnceLock<Regex> = OnceLock::new();
static BING_SNIPPET_RE: OnceLock<Regex> = OnceLock::new();

fn get_title_re() -> &'static Regex {
    TITLE_RE.get_or_init(|| {
        Regex::new(r#"<a[^>]*class=\"result__a\"[^>]*href=\"([^\"]+)\"[^>]*>(.*?)</a>"#)
            .expect("title regex pattern is valid")
    })
}

fn get_snippet_re() -> &'static Regex {
    SNIPPET_RE.get_or_init(|| {
        Regex::new(
            r#"<a[^>]*class=\"result__snippet\"[^>]*>(.*?)</a>|<div[^>]*class=\"result__snippet\"[^>]*>(.*?)</div>"#,
        )
        .expect("snippet regex pattern is valid")
    })
}

fn get_tag_re() -> &'static Regex {
    TAG_RE.get_or_init(|| Regex::new(r"<[^>]+>").expect("tag regex pattern is valid"))
}

fn get_bing_result_re() -> &'static Regex {
    BING_RESULT_RE.get_or_init(|| {
        Regex::new(r#"(?is)<li[^>]*class=\"[^\"]*\bb_algo\b[^\"]*\"[^>]*>(.*?)</li>"#)
            .expect("bing result regex pattern is valid")
    })
}

fn get_bing_title_re() -> &'static Regex {
    BING_TITLE_RE.get_or_init(|| {
        Regex::new(r#"(?is)<h2[^>]*>.*?<a[^>]*href=\"([^\"]+)\"[^>]*>(.*?)</a>"#)
            .expect("bing title regex pattern is valid")

View on GitHub (pinned to 0c42157ee5)