rtk-ai/rtk · error
invalid nextest starting regex
Error message
invalid nextest starting regex
What it means
Panic from `.expect("invalid nextest starting regex")` after `regex::Regex::new` for the `Starting N tests across M binaries` pattern in `filter_cargo_nextest` (src/cmds/rust/cargo_cmd.rs). Same class as the summary-regex panic: the regex crate rejects a syntactically invalid pattern and the expect converts it into an abort on the first invocation of the filter.
Solutions
- Correct the regex literal syntax and re-run `cargo test filter_cargo_nextest`.
- Move the regex into a `LazyLock<Regex>` static so compilation happens once and never on the per-call hot path.
- Adopt the fallback pattern (return a Result and run the raw command) if regex construction can ever fail at runtime.
Example fix
// before
let starting_re = regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex");
// after
static STARTING_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex")
}); Defensive patterns
Strategy: try-catch
Validate before calling
// validate every hardcoded pattern at startup or in tests
#[test]
fn starting_regex_is_valid() {
regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)").unwrap();
} Try / catch
let starting_re = match regex::Regex::new(STARTING_PAT) {
Ok(re) => re,
Err(e) => panic!("invalid nextest starting regex: {e}"), // keep message
}; Prevention
- Keep regex construction in LazyLock statics per repo rules
- Preserve the regex crate's error text in the panic message
- Check balanced groups after editing alternations like (?:y|ies)
When it happens
Trigger: A syntax error introduced into the hardcoded starting-line pattern (e.g. `binar(?:y|ies)` group corrupted, dangling `\d+` escape, unclosed alternation); the panic surfaces when `filter_cargo_nextest` is first called by its unit tests.
Common situations: Manual edits matching a new cargo-nextest banner format, copy-paste mistakes breaking the `(?:y|ies)` group, or accidental removal of a closing parenthesis during refactoring.
Related errors
- invalid ctest result prefix regex
- invalid ctest result terminator regex
- invalid ctest start regex
- invalid ctest summary regex
- invalid ctest time regex
AI-assisted analysis of rtk-ai/rtk@0924356b4c (2026-09-19).
Data as JSON: /api/errors/d861c9361acc0e38.
Report an issue: GitHub.
Appendix: source
Thrown at src/cmds/rust/cargo_cmd.rs:639
}
let mut block = header.clone();
if !body.is_empty() {
block.push('\n');
block.push_str(&body.join("\n"));
}
failures.push(block);
header.clear();
body.clear();
}
/// Filter cargo nextest output - show failures + compact summary
fn filter_cargo_nextest(output: &str) -> String {
let summary_re = regex::Regex::new(
r"Summary \[\s*([\d.]+)s\]\s+(\d+) tests? run:\s+(\d+) passed(?:,\s+(\d+) failed)?(?:,\s+(\d+) skipped)?"
).expect("invalid nextest summary regex");
let starting_re = regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex");
let mut failures: Vec<String> = Vec::new();
let mut in_failure_block = false;
let mut past_summary = false;
let mut current_failure_header = String::new();
let mut current_failure_body = Vec::new();
let mut summary_line = String::new();
let mut binaries: u32 = 0;
let mut has_cancel_line = false;
for line in output.lines() {
let trimmed = line.trim();
// Strip compilation noise
if trimmed.starts_with("Compiling")
|| trimmed.starts_with("Downloading")
|| trimmed.starts_with("Downloaded")
|| trimmed.starts_with("Finished")View on GitHub (pinned to 0924356b4c)