CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/Claude Code
Claude Code/2026-05-10Intermediate

Why Claude Code's Glob and Grep Return Zero Results

When Claude Code's Glob or Grep tool returns no matches even though the files clearly exist, the cause is almost always one of four things. Here's how to triage.

claude-code129troubleshooting87glob2grep2tools

You ask Claude Code to find every TSX file in your project with Glob, and it returns nothing. You drop into your terminal, run find . -name '*.tsx', and several hundred results scroll past. The first time I saw this, I rubbed my eyes for a full minute. The files are there. The pattern looks right. Only Claude Code disagrees.

Once Claude Code became part of my daily workflow as an indie developer juggling several repositories at once, I ran into this "invisible file" problem more times than I'd like to admit — usually right after switching into a monorepo, or a project where build output sits next to source. In nearly every case the root cause is one of four things: .gitignore exclusion, dotfile exclusion, a subtle pattern mismatch, or a workspace boundary the model can't cross. What follows is the triage flow I now run automatically whenever Glob or Grep claims a directory is empty.

The most common culprit: .gitignore

In my experience, seven or eight times out of ten the answer is .gitignore. Claude Code's Glob is built on top of ripgrep, and ripgrep respects your gitignore rules by default. That means node_modules/, dist/, .next/, build/, and any folder you've excluded from version control simply does not exist as far as Glob is concerned.

You'll hit this most often when:

  • You want to read a specific file inside node_modules/ for a dependency
  • You're inspecting a dist/ or build/ artifact
  • You're peeking at .next/ or .turbo/ cache contents
  • You're looking for a .env.local or other dotfile at the project root
  • You're after a workflow definition under .github/workflows/

That last case is two problems at once. .github/ is technically tracked by git, but it starts with a dot — and ripgrep, by default, ignores hidden directories. The same holds for .vscode/, .husky/, and similar tooling folders.

How to confirm

From your terminal:

# Confirm the files actually exist
find . -type f -name '*.tsx' | head -20
 
# Same check, skipping node_modules manually
find . -type f -name '*.tsx' -not -path '*/node_modules/*' | head -20

If find produces results that Glob does not, you're almost certainly looking at gitignore or dotfile exclusion.

The fix

The cleanest approach is to ask Claude Code to use Bash with explicit ripgrep flags. I include this instruction in my opening prompt now:

# Force ripgrep to include hidden + ignored files
rg --hidden --no-ignore --files | grep -E '\.(tsx?|jsx?)$'
 
# Search for a pattern across everything
rg --hidden --no-ignore -l 'useEffect' src/

There is no flag on the Glob tool itself to override gitignore. When I genuinely need to search ignored content, I bypass Glob entirely and shell out.

Why Grep misses lines you can clearly see

The Grep tool is also ripgrep underneath. Three subtleties trip people up.

Literal braces

If you're hunting Go's interface{} or a TypeScript empty object, the braces are ripgrep metacharacters. They need escaping.

# Wrong — unintended matches
rg 'interface{}' .
 
# Right — escape the braces
rg 'interface\{\}' .

I lost half an hour late last year searching a Go codebase for chan struct{} before remembering this. Bash's grep doesn't require the escape; ripgrep does. Small detail, real time sink.

Multiline mode is off by default

Claude Code's Grep tool defaults to single-line matching. A pattern that spans from struct { down to a field several lines below will return zero hits unless you explicitly pass multiline: true. The moment you realize you're trying to match across line breaks, ask Claude to set the multiline flag — it is a one-argument fix that saves a long debugging detour.

File-type filters are narrower than you think

type: 'js' matches .js files only. It does not include .jsx, .ts, or .tsx. Use a brace-expanded glob instead.

# Cover both JavaScript and TypeScript variants
rg 'pattern' --glob '*.{js,jsx,ts,tsx}'
 
# type filter is per-extension-group, not per-language
rg 'pattern' --type ts   # .ts only — .tsx is a different group

The same kind of pattern-syntax pitfall shows up in Claude Code's Edit tool when old_string isn't found, and the underlying mental model is the same: small differences in how a tool interprets your input change the result drastically.

Pattern syntax: the small, sharp edges

A few Glob patterns I see misused regularly:

  • **/*.tsx — recursive, matches any depth. Correct
  • **/*.{ts,tsx} — brace expansion, also works
  • src/** — captures everything under src, but folders themselves are included
  • src/**/* — files only, usually what you want
  • !**/test/** — negation. Claude Code's Glob does not currently support negation patterns directly. Use Bash with ripgrep filters when you need to exclude

I once typed *.tsx when I meant **/*.tsx and panicked because "no components exist anywhere." The leading **/ is what makes the pattern recursive. Without it, you're matching only files at the current directory level.

When the file is outside the workspace

Claude Code, by default, only sees files under the directory where the session started. If you want it to look at a parent directory or a sibling repository, one of three things needs to happen:

  • Run /add-dir <path> to grant access to additional roots
  • Pass an absolute path to Read directly
  • Drop into Bash and run find ~/another-project -name '*.ts' from outside the boundary

When I'm doing a refactor that crosses two or three repositories, I always run /add-dir for each at the start of the session. Skipping this step and asking Claude to "look at the implementation in the other repo" is a reliable way to get a confident "0 results" back.

Read versus Glob asymmetry

Read is more forgiving than Glob. If you give it an absolute path, it can usually open the file even if the path isn't in your allowed roots. Glob and Grep are stricter — they only search inside permitted directories. So you can read a file you cannot find. If you need to discover files first, run /add-dir before searching.

Claude Code's Read tool silently truncating large files at 2,000 lines covers a different Read-side surprise. Reading the two together gives you a fuller picture of how the file-touching tools behave.

When nothing else explains it

If gitignore, hidden files, patterns, and workspace boundaries are all ruled out, I move on to filesystem-level causes. The order I work through:

# 1. Case sensitivity (macOS often is case-insensitive, Linux isn't)
ls -la src/Components 2>&1
ls -la src/components 2>&1
 
# 2. Broken symlinks
find . -type l ! -exec test -e {} \; -print
 
# 3. Invisible characters in filenames (NBSP, zero-width space)
ls src/ | cat -A
 
# 4. Verify the file exists at all
stat src/components/Button.tsx

Broken symlinks are silently skipped by Glob. I once spent an evening confused by a pnpm workspace that had stale symlinks left over from a previous package layout. Removing the orphaned links and re-running pnpm install was the fix.

A diagnostic order I run mentally

When a search comes back empty, I now run a fixed sequence in my head before getting frustrated. It takes about thirty seconds end-to-end and saves me from re-asking Claude in increasingly desperate tones.

First, I ask whether the path I'm searching is gitignored. If the answer is "probably yes, that's a build output," I switch to Bash and rg --hidden --no-ignore immediately. Second, I check whether the file lives under a dotfile directory like .github/ or .vscode/. Third, I look at the pattern itself for anything ripgrep would treat as a metacharacter. Fourth, I ask whether the file might be outside the current workspace boundary. Only after all four of those return a clean "no" do I move on to the filesystem-level checks below.

Almost every dead end I have hit fits one of those first four buckets. The filesystem causes — broken symlinks, case sensitivity, invisible characters — are real but rare in comparison.

A small habit that prevents most of this

The change that helped me most wasn't technical — it was prompting. I now include three explicit hints at the start of any session that involves searching:

  • "If you need to include gitignored or hidden files, please use Bash with rg --hidden --no-ignore"
  • "If a file might live outside the current workspace, suggest /add-dir first"
  • "If Glob returns zero results, fall back to find in Bash before giving up"

That short paragraph at the top of a prompt has eliminated the majority of "I can't find that file" detours from my sessions. Telling the model where the boundaries are turns out to be cheaper than letting it hit them.

Common Bash tool execution errors in Claude Code reinforces a related habit: deciding when to reach for Bash versus a specialized tool is itself a debugging skill. The faster you make that call, the less time the session loses.

If you're staring at a zero-result Glob right now, my first move would be: drop into Bash, run rg --hidden --no-ignore --files | grep <your-pattern>, and see whether the file shows up. That single command resolves the case more often than not.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-04-30
Why Claude Code Skips .gitignore Files in Search — and How to Pull Them in When You Need Them
When .env.example or dist/ won't show up in Claude Code's Glob and Grep, .gitignore is the reason. Here's why it happens, plus three concrete ways through it: the Read tool, --no-ignore flags, and selective gitignore overrides.
Claude Code2026-06-18
When a Broken settings.json Stops Claude Code From Starting — Safe Mode and How to Split Your Config
How to find which config layer is broken when a settings.json syntax error stops Claude Code from starting, recover in minutes, and structure your settings so an automated pipeline can't quietly break itself.
Claude Code2026-06-10
When git add -A Sweeps Up .bak Backups — The Quiet Trap of In-Place Fix Scripts
How .bak backups left by sed -i and homegrown --fix scripts get silently swept into production by git add -A, why it is so easy to miss, and how scoped adds and .gitignore close the gap for good.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →