Grep tool silently returns zero results for invalid `type` (e.g. `tsx`) instead of surfacing rg's validation error
Summary
The Grep tool accepts a type argument that is forwarded to ripgrep's --type. When the value is not a registered rg type (e.g. "tsx", which is not a built-in — .tsx files belong to ts), ripgrep exits non-zero with unrecognized file type: tsx. The Grep tool wrapper appears to swallow that error and translate it into numFiles: 0 / "No files found" rather than reporting the validation failure.
The model trusts the empty result and stops investigating, causing false-negative searches that send agents down phantom-bug rabbit holes.
Repro
In any project containing .tsx files with a known pattern:
echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Use the Grep tool with these EXACT params: pattern=\"Gauges\", path=\".\", type=\"tsx\", output_mode=\"files_with_matches\". Just call it once."}]},"parent_tool_use_id":null}' \
| claude --print --input-format stream-json --output-format stream-json --model claude-sonnet-4-6
Observed in the tool_use_result frame:
{"mode":"files_with_matches","filenames":[],"numFiles":0}
The same call with type removed (or type: "ts", which is the correct rg type and covers .ts + .tsx) returns the expected matches.
For comparison, running rg directly:
$ rg --type tsx Gauges
rg: unrecognized file type: tsx
$ echo $?
2
Expected
Either:
- The tool surfaces the rg validation error in the result (
{"error": "unrecognized file type: tsx — try \"ts\" or use the glob field"}), so the model knows to retry, or - The tool normalizes common aliases (
tsx → ts,jsx → js) before calling rg.
Silently returning zero matches is the worst of both worlds — it looks like a clean answer.
Impact
Hit this debugging an agent harness. The agent passed type: "tsx" (a very natural choice given how prevalent TypeScript JSX is), got "No matches found," concluded the symbol didn't exist, and looped 25 tool calls trying to figure out a phantom missing-code bug. Models default to tsx because the file extension and the type name are intuitively the same.
Workaround
Until then, prompt agents to use type: "ts" (covers both extensions) or glob: "**/*.tsx".
Environment
- claude-code 2.1.126
- macOS 25.4.0 / arm64
- Reproduced both directly from a shell and via a stream-json wrapper subprocess.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗