Mintplex-Labs/anything-llm · error · Error

${result.stderr || `ripgrep exited with code ${result.status

Error message

${result.stderr || `ripgrep exited with code ${result.status}`}

What it means

Thrown by listFilesWithRipgrep after spawnSync runs the bundled ripgrep binary in --files mode. Ripgrep exit code 0 means success, 1 means no matches (not an error), and anything >1 is a real failure (bad flag, permission denied, unreadable path, binary crash, or maxBuffer exceeded). The error surfaces whatever ripgrep wrote to stderr, or a generic exit-code message if stderr is empty.

Source

Thrown at server/utils/agents/aibitat/plugins/filesystem/search-files.js:292

  const args = [
    "--files", // List files instead of searching content
    "--no-ignore", // Search all files, even those in .gitignore
  ];

  // Add glob patterns (ripgrep uses --glob for filtering --files output)
  for (const pattern of patterns) args.push("--glob", pattern);
  for (const exclude of excludePatterns) args.push("--glob", `!${exclude}`);

  // The "--" prevents searchPath from being parsed as an option if it starts with "-"
  // (defense against argument injection attacks)
  args.push("--", searchPath);
  const result = spawnSync(rgPath, args, {
    encoding: "utf-8",
    maxBuffer: 10 * 1024 * 1024,
  });

  if (result.status > 1) {
    throw new Error(
      result.stderr || `ripgrep exited with code ${result.status}`
    );
  }

  // unique files
  const files = new Set();
  if (!result.stdout) return { files: Array.from(files), method: "ripgrep" };

  const lines = result.stdout.trim().split("\n").filter(Boolean);
  for (const line of lines) {
    files.add(line);
    if (files.size >= maxResults) break;
  }

  return { files: Array.from(files), method: "ripgrep" };
}

/**

View on GitHub (pinned to 526360e320)

Solutions

  1. Check the stderr fragment in the error message — ripgrep usually states the exact problem (e.g. 'permission denied', 'regex error').
  2. Verify the searchPath exists and is readable by the AnythingLLM process user (ls -la <path>; run id to confirm the user).
  3. If the directory is enormous, narrow the search with include/exclude glob patterns or reduce the tree depth to stay under the 10MB buffer.
  4. Run the same ripgrep invocation manually to reproduce: <rgPath> --files --no-ignore --glob '<pattern>' -- '<searchPath>' and inspect the exit code.
  5. If spawnSync itself failed (result.status === null), check that the @vscode/ripgrep binary path is valid and the binary has execute permissions.

Example fix

// before
const result = spawnSync(rgPath, args, {
  encoding: "utf-8",
  maxBuffer: 10 * 1024 * 1024,
});
if (result.status > 1) {
  throw new Error(result.stderr || `ripgrep exited with code ${result.status}`);
}

// after — handle signal/null-status crashes and surface spawn errors too
const result = spawnSync(rgPath, args, {
  encoding: "utf-8",
  maxBuffer: 10 * 1024 * 1024,
});
if (result.error) {
  throw new Error(`Failed to launch ripgrep: ${result.error.message}`);
}
if (result.signal) {
  throw new Error(`ripgrep killed by signal ${result.signal}`);
}
if (result.status > 1) {
  throw new Error(result.stderr || `ripgrep exited with code ${result.status}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require("fs");
// Validate path before calling the listing tool
if (!fs.existsSync(searchPath)) {
  throw new Error(`searchPath does not exist: ${searchPath}`);
}
try { fs.accessSync(searchPath, fs.constants.R_OK); }
catch { throw new Error(`searchPath is not readable: ${searchPath}`); }
// Validate glob patterns are syntactically plausible
for (const p of patterns) {
  if (p.includes("{" )) {
    const opens = (p.match(/{/g) || []).length;
    const closes = (p.match(/}/g) || []).length;
    if (opens !== closes) throw new Error(`Unbalanced braces in glob: ${p}`);
  }
}

Type guard

/** @param {string} p */
function isValidSearchPath(p) {
  return typeof p === "string" && p.length > 0 && !p.includes("\0");
}

Try / catch

try {
  const result = listFilesWithRipgrep({ searchPath, patterns, excludePatterns, maxResults });
  // use result.files
} catch (e) {
  if (e.message.includes("permission denied")) {
    // handle access issue — notify user or fall back
  }
  logger.error(`File listing failed: ${e.message}`);
  return { files: [], error: e.message };
}

Prevention

When it happens

Trigger: Calling the agent file-listing tool with a searchPath that does not exist, is not readable by the process, contains a path ripgrep cannot traverse, or when the 10MB maxBuffer is exceeded by a very large directory tree. Also triggered by passing malformed glob patterns to --glob that ripgrep rejects.

Common situations: Docker container where the mounted volume has restrictive ownership; searching a node_modules or build output directory with thousands of files blowing the 10MB stdout buffer; searchPath pointing to a deleted or renamed folder; glob syntax like **/*.{js that has an unclosed brace.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/b019ec9c6ac023af. Report an issue: GitHub.