fix(grep): surface error on exit code >= 2 instead of false "0 matches"#2465
Conversation
hgunduzoglu
left a comment
There was a problem hiding this comment.
Checked this out and tested locally (macOS arm64). The core fix is correct — broadening the gate to exit_code >= 2 matches grep/rg convention, and all three paths behave right:
| rg exit | meaning | before | this PR |
|---|---|---|---|
| 0 | matches | grouped output | grouped output ✓ |
| 1 | no match | 0 matches |
0 matches, exit 1 ✓ (legit empty result preserved) |
| ≥2 | real error | 0 matches (false negative) |
grep failed with exit code N on stderr, exit propagated ✓ |
Verified with a fake rg exiting 2: it now surfaces grep failed with exit code 2 and exits 2 instead of the misleading 0 matches. The new integration test passes here. Nice — this closes a genuine false-negative footgun.
One blocker for CI, though: tests/grep_error_test.rs has an unconditional use std::os::unix::fs::PermissionsExt; (line 6) with no cfg(unix) gate. std::os::unix doesn't exist on Windows, so the integration-test crate will fail to compile on the Windows CI target (RTK ships a Windows build, and cli-testing.md marks cross-platform a 🔴 critical concern). It's the only file under tests/ that touches std::os::unix.
Two small options:
- Gate the whole file: add
#![cfg(unix)]at the top (simplest — the test simulates a brokenrgvia a chmod'd shell script, which is unix-only anyway), or #[cfg(unix)]on the test fn +#[cfg(unix)] use std::os::unix::....
Either keeps the Windows build green while preserving the unix coverage. Everything else looks good — the fix itself is solid and well-targeted.
|
Thanks for the review @hgunduzoglu — agreed, that's a real Windows compile break, not a nit. Fixed in Verified: cross- |
Exit codes >= 2 signal real errors in grep/rg (bad regex, tool crash, missing binary). rtk was only checking the narrow case exit_code == 2 with non-empty stderr, letting any other error exit masquerade as a clean "0 matches" false negative. Now any exit code >= 2 surfaces the error to stderr instead of printing a false zero-match result. Fixes rtk-ai#2461 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The test simulates a broken `rg` via a chmod'd shell script (from_mode, PermissionsExt) which is unix-only. The unconditional `use std::os::unix` broke compilation of the integration-test crate on the Windows CI target. Gate the whole file so Windows stays green while preserving unix coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap the rtk binary path expression per rustfmt to satisfy `cargo fmt --all -- --check` on CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address KuSh review on rtk-ai#2465: - Move the `exit_code >= 2` decision into a pure `is_grep_error_exit` function and unit-test it directly (0/1 = normal, >=2 = error), instead of faking the rg binary in an integration test. - Drop the GREP_ERROR_EXIT const; the doc comment on the function conveys the grep/rg exit convention. - Remove tests/grep_error_test.rs (faked binary) in favour of the unit test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a228dc0 to
39ca858
Compare
Summary
rtk grepprints "0 matches for ''" when the underlying search tool exits with an error code >= 2, even when matches exist and the tool simply failed to run. This is a false negative — LLM agents interpret it as a clean empty result and act on incorrect information.Root cause:
grep_cmd.rs:386-399handled only the narrow caseexit_code == 2 && stderr non-empty. grep/rg convention: exit 1 = no match (normal), exit >= 2 = real error (bad regex, binary crash, missing tool). Any error exit that fell outside the narrow window silently became "0 matches".Fix: Broadened the gate to
exit_code >= 2. All error exits now surface to stderr (prefixed with the exit code for diagnostics) and never print the misleading "0 matches" message. Exit 0 and 1 behavior is unchanged.Fixes #2461
Test verification (RED → GREEN)
With the fix reverted, the new test fails (RED):
With the fix applied, the test passes (GREEN):
Full baseline: 2196 tests pass, 0 fail (2195 existing + 1 new).
🤖 Generated with Claude Code