JuliusBrussee/caveman · error

caveman-code: neither rg nor grep is available

Error message

caveman-code: neither rg nor grep is available

What it means

The grep tool in packages/agent/src/code.ts first tries to spawn ripgrep ('rg'); if spawning fails it falls back to 'grep -rnI -m N -E'. If both spawn attempts fail (spawnFailed on both), it throws 'caveman-code: neither rg nor grep is available', meaning no search backend exists on the host or PATH.

Solutions

  1. Install ripgrep on the host (apt install ripgrep / brew install ripgrep / cargo install ripgrep) — preferred backend.
  2. Alternatively ensure GNU/BSD grep is installed and on PATH (apt install grep, apk add grep).
  3. Fix the PATH seen by the process (e.g. PATH=/usr/bin:/bin:...) so existing binaries are found.
  4. If running in a minimal container, add rg to the image: COPY --from or the package manager in the Dockerfile.
  5. Verify availability: `command -v rg || command -v grep` in the same environment the agent runs in.

Example fix

# before (Dockerfile)
FROM gcr.io/distroless/nodejs
# after
FROM node:22-slim
RUN apt-get update && apt-get install -y ripgrep
Defensive patterns

Strategy: fallback

Validate before calling

const { execFileSync } = require("child_process");
const hasSearchBackend = ["rg", "grep"].some((b) => {
  try { execFileSync(b, ["--version"], { stdio: "ignore" }); return true; }
  catch { return false; }
});
if (!hasSearchBackend) throw new Error("Install ripgrep before using the grep tool");

Try / catch

try {
  await grep({ pattern, path });
} catch (e) {
  if (e.message.includes("neither rg nor grep is available")) {
    console.error("No search backend on PATH; install ripgrep or use a JS-based search fallback.");
  } else throw e;
}

Prevention

When it happens

Trigger: Running the grep tool on a host/container where neither rg nor grep is installed, or neither binary is on the PATH inherited by the process; a stripped-down Docker image (e.g. alpine without grep, distroless images) or a sandboxed workspace root without system tools.

Common situations: Distroless/minimal CI images; Windows hosts without grep and ripgrep not installed; custom PATH overrides in the agent environment excluding /usr/bin; containerized eval sandboxes that intentionally omit system utilities.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/09dc660b71472d0f. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/code.ts:286

    result: "inline",
    timeoutMs: READ_TIMEOUT_MS,
    async execute(input, signal) {
      const root = await workspaceRoot();
      const scope = input.path === undefined ? root : await contained(input.path);
      const relativeScope = scope === root ? "." : relative(root, scope);
      const ripgrep = [
        "--line-number", "--no-heading", "--color", "never",
        "--max-count", String(GREP_MAX_MATCHES),
        ...(input.glob === undefined ? [] : ["--glob", input.glob]),
        "--regexp", input.pattern, "--", relativeScope,
      ];
      let run = await runProcess("rg", ripgrep, root, READ_TIMEOUT_MS, signal);
      if (run.spawnFailed) {
        run = await runProcess("grep", [
          "-rnI", "-m", String(GREP_MAX_MATCHES), "-E", "-e", input.pattern, "--", relativeScope,
        ], root, READ_TIMEOUT_MS, signal);
      }
      if (run.spawnFailed) throw new Error("caveman-code: neither rg nor grep is available");
      const body = run.output.trim() === "" ? "no matches" : run.output;
      const text = capOutput(body, caps.grep);
      record(`grep:${input.pattern}`, text);
      return text;
    },
  });

  const bashTool = tool({
    name: "bash",
    description:
      "Run one shell command in the workspace and return its combined stdout and stderr. " +
      `Times out after ${BASH_TIMEOUT_MS} ms; output is capped at ${caps.bash} bytes.`,
    input: schema.object({
      command: schema.string(),
      timeoutMs: schema.optional(schema.integer()),
    }),
    effect: "external",
    result: "inline",

View on GitHub (pinned to 3ee70a1026)