sinelaw/fresh · error

ag exited with code

Error message

ag exited with code ${r.exit_code}: ${r.stderr}

What it means

The live_grep plugin's `ag` (the_silver_searcher) provider throws this when the spawned ag process exits with a code other than 0 or 1 (1 means 'no matches' and is handled as an empty result). Codes like 2 indicate ag itself failed — typically a bad regex, bad flags, or an unusable search directory. The stderr text appended to the message carries ag's own diagnostic.

Solutions

  1. Fix the query pattern if regex mode is enabled (validate or escape it).
  2. Run `ag <pattern>` by hand in the same cwd and read stderr for the underlying cause.
  3. Confirm ag is installed and reasonably current (`ag --version`); upgrade if flags are unsupported.
  4. Prefer the ripgrep provider (higher priority) if ag keeps failing.

Example fix

// before
const r = await editor.spawnProcess("ag", args, cwd);
// after
// validate the regex before spawning when regex mode is on
if (regex) { try { new RegExp(query); } catch (e) { throw new Error(`invalid pattern: ${query}`); } }
const r = await editor.spawnProcess("ag", args, cwd);
Defensive patterns

Strategy: try-catch

Validate before calling

if (regexMode) { try { new RegExp(query); } catch { throw new Error(`invalid regex: ${query}`); } }
await editor.spawnProcess("ag", ["--version"], cwd); // backend present check

Type guard

function isSpawnResult(r) { return r && typeof r.exit_code === "number" && typeof r.stderr === "string"; }

Try / catch

try {
  results = await agProvider.search(query, opts);
} catch (e) {
  if (/ag exited with code/.test(String(e))) {
    results = await rgProvider.search(query, opts); // fall back to another backend
  } else { throw e; }
}

Prevention

When it happens

Trigger: Invoking the live-grep ag provider when: (1) the query is an invalid regex in regex mode (ag exits 2), (2) an unsupported flag combination is passed (wholeWord/wholePath variants on unusual ag versions), or (3) the cwd is missing or unreadable.

Common situations: Ag not installed properly or an old version lacking flags like --word-regexp/--literal; typing malformed regex like '(' with regex mode on; searching from a deleted or unreadable working directory.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/6c3266b6ed32632b. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/plugins/live_grep.ts:506

    const args = [
      "--column",
      "--numbers",
      "--nogroup",
      "--nocolor",
      "--smart-case",
      "--ignore", ".git",
      "--ignore", "node_modules",
      "--ignore", "target",
      "--ignore", "*.lock",
    ];
    if (regex === false) args.push("--literal");
    if (wholeWord) args.push("--word-regexp");
    args.push("--", query);
    const r = await editor.spawnProcess("ag", args, cwd);
    if (r.exit_code === 0 || r.exit_code === 1) {
      return parseGrepOutput(r.stdout, maxResults, (msg) => editor.debug(msg)) as GrepMatch[];
    }
    throw new Error(`ag exited with code ${r.exit_code}: ${r.stderr}`);
  },
});

/** The cwd git-grep should run in: the caller's `preferred` cwd when it is
 *  itself inside a repo, else the active buffer's dir (monorepo: the workspace
 *  root isn't a repo but the open file is). Returns null when neither is a
 *  repo. Used by both `isAvailable` and `search` so they can't disagree. */
async function gitGrepCwd(preferred: string): Promise<string | null> {
  const inRepo = await editor.spawnProcess(
    "git", ["rev-parse", "--is-inside-work-tree"], preferred
  );
  if (inRepo.exit_code === 0) return preferred;
  const cand = gitCwdCandidate(editor);
  if (cand !== preferred) {
    const r = await editor.spawnProcess(
      "git", ["rev-parse", "--is-inside-work-tree"], cand
    );
    if (r.exit_code === 0) return cand;

View on GitHub (pinned to 67894ca546)