{"record":{"id":"c9835a775bfe3623","repo":"charmbracelet/crush","slug":"ripgrep-not-found-in-path","errorCode":null,"errorMessage":"ripgrep not found in $PATH","messagePattern":"ripgrep not found in \\$PATH","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/grep.go","lineNumber":221,"sourceCode":"\t// Use a stable sort so that the multiple matches a single file can\n\t// contribute (all sharing the same modTime) keep their original\n\t// line order and stay grouped together in the rendered output.\n\tsort.SliceStable(matches, func(i, j int) bool {\n\t\treturn matches[i].modTime.After(matches[j].modTime)\n\t})\n\n\ttruncated := len(matches) > limit\n\tif truncated {\n\t\tmatches = matches[:limit]\n\t}\n\n\treturn matches, truncated, nil\n}\n\nfunc searchWithRipgrep(ctx context.Context, pattern, path, include string) ([]grepMatch, error) {\n\tcmd := getRgSearchCmd(ctx, pattern, path, include)\n\tif cmd == nil {\n\t\treturn nil, fmt.Errorf(\"ripgrep not found in $PATH\")\n\t}\n\n\t// Only add ignore files if they exist\n\tfor _, ignoreFile := range []string{\".gitignore\", \".crushignore\"} {\n\t\tignorePath := filepath.Join(path, ignoreFile)\n\t\tif _, err := os.Stat(ignorePath); err == nil {\n\t\t\tcmd.Args = append(cmd.Args, \"--ignore-file\", ignorePath)\n\t\t}\n\t}\n\n\toutput, err := cmd.Output()\n\tif err != nil {\n\t\tif exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 1 {\n\t\t\treturn []grepMatch{}, nil\n\t\t}\n\t\treturn nil, err\n\t}\n","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/grep.go#L203-L239","documentation":"The grep tool's ripgrep-based search path could not locate the rg executable, so getRipgrepSearchCmd returned nil. The tool requires ripgrep as an external dependency and cannot perform the search without it.","triggerScenarios":"searchWithRipgrep is invoked and getRgSearchCmd(ctx, pattern, path, include) returns nil — i.e. exec.LookPath(\"rg\") fails because ripgrep is not installed or not on PATH.","commonSituations":"Fresh machines or CI containers without ripgrep; minimal Docker images; PATH modified so rg's location (e.g. /usr/local/bin, ~/go/bin, ~/.cargo/bin) is missing; crush installed via a method that doesn't bundle rg.","solutions":["Install ripgrep: `brew install ripgrep`, `apt install ripgrep`, `dnf install ripgrep`, or `cargo install ripgrep`","Confirm `rg --version` runs in the same shell/environment crush uses","Fix PATH so it includes rg's directory (e.g. export PATH=\"$HOME/.cargo/bin:$PATH\")","Restart crush after installing so the PATH lookup succeeds"],"exampleFix":"// before\ncmd := getRgSearchCmd(ctx, pattern, path, include)\nif cmd == nil {\n    return nil, fmt.Errorf(\"ripgrep not found in $PATH\")\n}\n// after\ncmd := getRgSearchCmd(ctx, pattern, path, include)\nif cmd == nil {\n    return nil, fmt.Errorf(\"ripgrep not found in $PATH; install it with 'brew install ripgrep' or 'apt install ripgrep'\")\n}","handlingStrategy":"fallback","validationCode":"if _, err := exec.LookPath(\"rg\"); err != nil {\n    // rg unavailable — skip ripgrep path or warn the user to install it\n}","typeGuard":"null","tryCatchPattern":"cmd := getRgSearchCmd(ctx, pattern, path, include)\nif cmd == nil {\n    return nil, fmt.Errorf(\"ripgrep not found in $PATH\")\n}","preventionTips":["Install ripgrep as part of environment setup (Dockerfile, CI, devcontainer)","Verify with `rg --version` after any toolchain change","Include ripgrep's install dir (e.g. ~/.cargo/bin) in PATH","Consider bundling rg or falling back to a pure-Go search when absent"],"tags":["ripgrep","dependency","path","environment"],"backgroundTag":"binary-not-found-in-path","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}