charmbracelet/crush · error
ripgrep: %w
Error message
ripgrep: %w
What it means
runRipgrep failed to obtain a stdout pipe from the ripgrep exec.Command. This is a rare process-setup failure that occurs before ripgrep itself runs, meaning the command could not even be wired for output capture.
Source
Thrown at internal/agent/tools/glob.go:138
return fsext.GlobGitignoreAwareCtx(ctx, walkPattern, walkRoot, limit)
}
func runRipgrep(cmd *exec.Cmd, searchRoot string, limit int) ([]string, error) {
// Stream ripgrep's stdout instead of buffering the whole file list.
// Over a huge root (e.g. $HOME) the full --files listing can be
// hundreds of MB; reading it all at once and then sorting allocated
// gigabytes. We read incrementally and stop once we have a bounded
// pool of candidates.
//
// We collect more than `limit` so the shortest-path preference below
// still has something to choose from, but the pool is capped so memory
// stays small (a few thousand paths) no matter how large the tree is.
candidatePool := max(limit*20, 1000)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("ripgrep: %w", err)
}
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("ripgrep: %w", err)
}
var matches []string
reader := bufio.NewReader(stdout)
for {
path, err := reader.ReadString(0)
if len(path) > 0 {
path = strings.TrimRight(path, "\x00")
if path != "" {
absPath := filepathext.SmartJoin(searchRoot, path)
if !fsext.SkipHidden(absPath) {
matches = append(matches, absPath)View on GitHub (pinned to 7944b8e522)
Solutions
- Check and raise the process file-descriptor limit (`ulimit -n`)
- Ensure runRipgrep is not reusing an exec.Cmd that already had Start() called
- Re-run the glob operation — this failure is typically transient
- Verify ripgrep is installed and functioning (`rg --version`)
Example fix
// before
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("ripgrep: %w", err)
}
// after
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("ripgrep: failed to create stdout pipe: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if runtime.GOOS != "windows" {
var lim syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err == nil && lim.Cur < 1024 {
lim.Cur = 4096
_ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim)
}
} Type guard
null
Try / catch
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("ripgrep: %w", err)
} // then cmd.Start(); never reuse the cmd after Wait Prevention
- Never reuse an exec.Cmd that has already started
- Raise RLIMIT_NOFILE in environments with many concurrent processes
- Create the pipe exactly once per command, before Start
- Treat as transient and retry once on failure
When it happens
Trigger: cmd.StdoutPipe() returns an error — almost always because the pipe could not be created (e.g. the command has already started, or an OS-level file-descriptor exhaustion).
Common situations: File descriptor limits (ulimit -n) exhausted under heavy parallel tool usage; reusing an already-started exec.Cmd; extremely constrained container environments.
Related errors
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/19e12d6b0bd4b2ab.
Report an issue: GitHub.