{"record":{"id":"0a85e08e6e7684fe","repo":"rtk-ai/rtk","slug":"invalid-nextest-summary-regex","errorCode":null,"errorMessage":"invalid nextest summary regex","messagePattern":"invalid nextest summary regex","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmds/rust/cargo_cmd.rs","lineNumber":636,"sourceCode":"fn flush_failure_block(header: &mut String, body: &mut Vec<String>, failures: &mut Vec<String>) {\n    if header.is_empty() {\n        return;\n    }\n    let mut block = header.clone();\n    if !body.is_empty() {\n        block.push('\\n');\n        block.push_str(&body.join(\"\\n\"));\n    }\n    failures.push(block);\n    header.clear();\n    body.clear();\n}\n\n/// Filter cargo nextest output - show failures + compact summary\nfn filter_cargo_nextest(output: &str) -> String {\n    let summary_re = regex::Regex::new(\n        r\"Summary \\[\\s*([\\d.]+)s\\]\\s+(\\d+) tests? run:\\s+(\\d+) passed(?:,\\s+(\\d+) failed)?(?:,\\s+(\\d+) skipped)?\"\n    ).expect(\"invalid nextest summary regex\");\n\n    let starting_re = regex::Regex::new(r\"Starting \\d+ tests? across (\\d+) binar(?:y|ies)\")\n        .expect(\"invalid nextest starting regex\");\n\n    let mut failures: Vec<String> = Vec::new();\n    let mut in_failure_block = false;\n    let mut past_summary = false;\n    let mut current_failure_header = String::new();\n    let mut current_failure_body = Vec::new();\n    let mut summary_line = String::new();\n    let mut binaries: u32 = 0;\n    let mut has_cancel_line = false;\n\n    for line in output.lines() {\n        let trimmed = line.trim();\n\n        // Strip compilation noise\n        if trimmed.starts_with(\"Compiling\")","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/rtk-ai/rtk/blob/0924356b4caba4989607227b7c8824d3d8098719/src/cmds/rust/cargo_cmd.rs#L618-L654","documentation":"Panic from `.expect(\"invalid nextest summary regex\")` after `regex::Regex::new` in `filter_cargo_nextest` (src/cmds/rust/cargo_cmd.rs). Rust's regex crate returns `Err` for syntactically invalid patterns, and the code turns that into a panic. Because the pattern is a hardcoded literal, this fires only at the first call to `filter_cargo_nextest` (i.e. in its unit tests), crashing the filter instead of degrading gracefully.","triggerScenarios":"Editing the hardcoded `Summary [...]` regex literal and introducing a syntax error (unbalanced `(?:...)` group, bad escape, invalid repetition); the panic then fires on every `filter_cargo_nextest` call, first observed when running the six filter_cargo_nextest unit tests.","commonSituations":"Hand-editing the nextest summary pattern to match a new cargo-nextest output format and mistyping an escape like `\\s` or leaving a group unclosed; regex crate version upgrades rarely matter here since the pattern is static.","solutions":["Fix the regex literal syntax — validate it with a quick `regex::Regex::new(r\"...\")` in a scratch test or at regex101 (Rust flavor).","Compile the regex once via a `static LazyLock<Regex>` instead of per-call `Regex::new(...).expect(...)`, per the repo's own regex rule.","If the pattern must stay dynamic, return `anyhow::Result` and fall back to raw output instead of panicking, following the repo's fallback pattern."],"exampleFix":"// before\nlet summary_re = regex::Regex::new(r\"Summary \\[\\s*([\\d.]+)s\\]...\")\n    .expect(\"invalid nextest summary regex\");\n// after\nstatic SUMMARY_RE: LazyLock<Regex> = LazyLock::new(|| {\n    Regex::new(r\"Summary \\[\\s*([\\d.]+)s\\]...\").expect(\"invalid nextest summary regex\")\n});","handlingStrategy":"try-catch","validationCode":"// compile-time-ish check: unit test that builds all filter regexes\n#[test]\nfn nextest_regexes_are_valid() {\n    regex::Regex::new(SUMMARY_PAT).unwrap();\n}","typeGuard":null,"tryCatchPattern":"match regex::Regex::new(SUMMARY_PAT) {\n    Ok(re) => re,\n    Err(e) => {\n        eprintln!(\"nextest summary regex invalid: {e}\");\n        return output.to_string(); // fallback: raw output\n    }\n}","preventionTips":["Compile regexes once in LazyLock statics, never inside the filter function","Validate regex literals with a dedicated unit test so CI fails on typos","Never panic in production filters — follow the repo fallback pattern (raw output)"],"tags":["rust","regex","panic"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"0924356b4caba4989607227b7c8824d3d8098719","analyzedAt":"2026-09-19T19:25:29.612Z","contentChangedAt":"2026-09-19T19:25:29.612Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}