rtk-ai/rtk · error
invalid nextest starting regex
Error message
invalid nextest starting regex
What it means
This panic fires when regex::Regex::new cannot compile the hardcoded nextest 'Starting' pattern (r"Starting \d+ tests? across (\d+) binar(?:y|ies)") at src/cmds/rust/cargo_cmd.rs:627-628, inside filter_cargo_nextest. The pattern is a string literal recompiled at runtime on every call, so the panic is only reachable after a developer edits the literal into an invalid regex — child output cannot trigger it. Like its sibling summary regex, it violates the repo's LazyLock rule for regex statics.
Source
Thrown at src/cmds/rust/cargo_cmd.rs:628
}
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 d977e1c316)
Solutions
- Validate the edited literal in isolation (scratch program or `cargo test` with a compile-only test) to get the precise syntax error, then fix it at src/cmds/rust/cargo_cmd.rs:627.
- Hoist into `static STARTING_RE: LazyLock<Regex>` per the repo regex convention, eliminating recompilation per call.
- Add a unit test asserting the regex matches "Starting 42 tests across 3 binaries" so regressions fail in `cargo test`, not in production runs.
Example fix
// before (src/cmds/rust/cargo_cmd.rs:627)
let starting_re = regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex");
// after
static STARTING_RE: std::sync::LazyLock<regex::Regex> = std::sync::LazyLock::new(|| {
regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex")
});
#[test]
fn nextest_starting_regex_matches() {
assert!(STARTING_RE.is_match("Starting 42 tests across 3 binaries"));
} Defensive patterns
Strategy: validation
Validate before calling
#[test]
fn nextest_starting_regex_compiles_and_matches() {
let starting = regex::Regex::new(r"Starting \d+ tests? across (\d+) binar(?:y|ies)")
.expect("invalid nextest starting regex");
assert!(starting.is_match("Starting 42 tests across 3 binaries"));
assert!(starting.is_match("Starting 1 test across 1 binary"));
} Prevention
- Move the pattern into a `static STARTING_RE: LazyLock<Regex>` next to the filter so it is a single reviewed constant instead of an inline literal compiled per call.
- Cover both pluralizations (binary/binaries, test/tests) in the compile-and-match unit test, since that alternation is the part most often edited incorrectly.
- Run `cargo test nextest` after touching any nextest pattern; the filter's tests are the only thing standing between a typo and a runtime panic.
- Keep raw strings (r"...") for all patterns so backslashes are regex escapes only — mixing escaped normal strings is a classic way to produce an invalid pattern.
When it happens
Trigger: Any invocation that calls filter_cargo_nextest (`rtk cargo nextest` or a hooked `cargo nextest`) after the literal was made invalid — e.g. renaming the `binar(?:y|ies)` alternation to `binar(y|ies` (unbalanced paren) or escaping a metachar wrongly. Regex::new executes unconditionally before the line loop, so the process panics even for output with no 'Starting' line.
Common situations: Contributor tweaks the pattern to also match nextest's 'Starting N tests across M binaries (M features)' variant, drops a closing paren or bracket, cargo build still succeeds (pattern is runtime data), and the first `rtk cargo nextest` run panics with this message — often noticed only in CI smoke tests or by an agent proxying test runs.
Related errors
- invalid nextest summary regex
- invalid regex patterns
- invalid regex
- stdout streaming thread panicked
- stderr streaming thread panicked
AI-assisted analysis of rtk-ai/rtk@d977e1c316 (2026-08-16).
Data as JSON: /api/errors/d861c9361acc0e38.
Report an issue: GitHub.