rtk-ai/rtk · error
invalid nextest summary regex
Error message
invalid nextest summary regex
What it means
This panic fires when regex::Regex::new cannot compile the hardcoded nextest summary pattern (r"Summary \[\s*([\d.]+)s\]...") inside filter_cargo_nextest (src/cmds/rust/cargo_cmd.rs:623-625). Because the pattern is a string literal, the regex crate parses it at runtime on every call; the only way to get Err is a developer editing the literal into an invalid regex (unbalanced `(` or `[`, bad escape, etc.) — no cargo nextest output can cause it. It also violates the repo rule (.claude/rules/rust-patterns.md) that all regex live in LazyLock statics, so the pattern is needlessly recompiled per invocation.
Source
Thrown at src/cmds/rust/cargo_cmd.rs:625
fn flush_failure_block(header: &mut String, body: &mut Vec<String>, failures: &mut Vec<String>) {
if header.is_empty() {
return;
}
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")View on GitHub (pinned to d977e1c316)
Solutions
- Fix the literal: paste the pattern into a scratch `fn main` with Regex::new(...).unwrap() or an online rust-regex checker to get the exact syntax error, then correct it in src/cmds/rust/cargo_cmd.rs:624.
- Hoist it into a module-level `static SUMMARY_RE: LazyLock<Regex>` with the same expect, matching the repo's LazyLock convention and removing the per-call recompile.
- Add a unit test that compiles the regex and matches a real summary line (e.g. "Summary [ 12.34s] 42 tests run: 40 passed, 2 failed") so an invalid pattern fails `cargo test` before shipping.
Example fix
// before (src/cmds/rust/cargo_cmd.rs:622)
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");
// after: compile once, fail fast and legibly
static SUMMARY_RE: std::sync::LazyLock<regex::Regex> = std::sync::LazyLock::new(|| {
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")
});
#[test]
fn nextest_summary_regex_matches() {
assert!(SUMMARY_RE.is_match("Summary [ 2.345s] 42 tests run: 41 passed, 1 failed"));
} Defensive patterns
Strategy: validation
Validate before calling
// Add next to filter_cargo_nextest — fails `cargo test` before any runtime panic:
#[test]
fn nextest_regexes_compile_and_match() {
let summary = 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");
assert!(summary.is_match("Summary [ 2.345s] 42 tests run: 41 passed, 1 failed"));
} Prevention
- Hoist every literal regex into a module-level `static X: LazyLock<Regex>` (the repo's own rule in .claude/rules/rust-patterns.md) so the pattern is written once and compiled once.
- Pair each filter regex with a unit test that both compiles it and matches a real nextest output line, so pattern edits fail CI instead of the first `rtk cargo nextest` run.
- When adapting a pattern for a new nextest output format, paste a captured fixture line into the test first, then change the regex until the test passes — never edit the pattern blind.
- Remember the rust regex crate has no backreferences or lookaround; keep patterns to literals, classes, groups, and repetition.
When it happens
Trigger: Any run that reaches filter_cargo_nextest — i.e. `rtk cargo nextest` or a hooked `cargo nextest` invocation — after the literal was edited into an invalid regex. Regex::new runs unconditionally at the top of the function, so the process panics before any output parsing, even when the run's output contains no Summary line at all. The crate still compiles because the pattern is an ordinary &str; nothing checks it at build time.
Common situations: A contributor adapts the pattern for a new nextest release's summary format (e.g. adding another optional group like (?:,\s+(\d+) skipped)?) and mistypes a bracket or parenthesis; CI is green unless a nextest fixture test executes; the first real `rtk cargo nextest` run then aborts with this message.
Related errors
- invalid nextest starting 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/0a85e08e6e7684fe.
Report an issue: GitHub.