Skip to content

Codex rg searches with no matches are rendered as failed tool calls #651

Description

@rubybrowncoat

Summary

When a Codex agent runs rg and the search finds nothing, Codeg shows the terminal tool call as failed, in red. Nothing failed. Ripgrep returns exit code 1 to mean "no matches were found."

I have hit this in conversation after conversation. A successful negative search looks like a broken command, and the agent reads it the same way I do, so it retries the search or falls back to slower file scanning.

The root cause is upstream, not in Codeg. Codeg is still the layer where a fix reaches users soonest.

Environment

  • Codeg Desktop 0.30.2
  • Windows
  • PowerShell
  • Codex agents through ACP

Reproduction

  1. Open a Codex conversation in Codeg.
  2. Search for a token that does not exist:
rg -n "__definitely_absent_token__" README.md
  1. The command writes nothing to stdout or stderr. Codeg labels the tool call failed.

A captured ACP transcript contains this terminal result:

{
  "_meta": {
    "terminal_exit": {
      "exit_code": 1,
      "signal": null
    }
  },
  "rawOutput": {
    "exit_code": 1,
    "formatted_output": ""
  },
  "status": "failed"
}

Repeated examples

I reproduced this in four separate Codeg conversations:

  • Conversation 117: rg -n -C 50 '"id": "CP-0090"|"id": "CP-0085"|"id": "CP-0084"' docs/backlog.json returned no output, marked failed.
  • Conversation 113: rg -n -i "Reconcile post-B-2 accessibility delta|post-B-2 accessibility|..." docs .github 2>$null returned no output, marked failed.
  • Conversation 90: a bounded rg search across the docs returned no output, marked failed.
  • Conversation 103: the compound case. An initial rg --files printed a valid filename, a later rg found nothing, and Codeg rendered the whole tool call as failed because the last process exited 1.

Real ripgrep errors look different. The same transcripts contain malformed regexes, missing paths, and invalid Windows globs, and every one of those wrote a diagnostic to stderr. Those should stay failures.

Why it happens

Ripgrep's documented exit contract is:

  • 0: a match was found
  • 1: no matches were found
  • 2: an actual error occurred

Codex reports a shell command as failed whenever its exit code is nonzero. openai/codex#8268 reports the same behavior upstream, and it is closed as not planned.

Codeg keeps that wire status as-is. In src-tauri/src/parsers/acp_native.rs the parser copies the incoming status and treats status == "failed" as is_error. The UI has no neutral state left to show for an expected empty result.

Expected behavior

Show an rg run that exits 1 with no matches neutrally. Something like:

  • No matches found, or
  • Completed, no matches

It should not get the same red failure treatment as a malformed regex, a missing path, a permission denial, or a process that never launched.

Possible approaches

ACP hands Codeg a failed status, so any fix here normalizes at the integration or presentation layer. Only when all of these hold:

  • the executed command is a standalone ripgrep search;
  • the exit code is 1;
  • there is no stderr or error diagnostic;
  • the process was not canceled or denied.

Another option: a neutral nonzero-exit state such as Exited 1, no output. Or let a command declare which exit codes count as success, without rewriting the underlying ACP record.

Please do not treat every exit code 1 as success. Real errors and compound shell commands need to keep their actual meaning. Regression tests should separate four cases:

  1. rg with matches, which is a success;
  2. rg with no matches and no diagnostics, which is a neutral no-match;
  3. malformed regex or missing path, which stays a failure;
  4. compound and pipelined commands, which keep the overall shell result or get shown without claiming every command in the chain failed.

Impact

  • Misleading red failure markers in otherwise healthy agent runs.
  • Agents read a valid negative search as a broken command or a broken environment.
  • Wasted retries and slower fallback scans.
  • When every fourth tool call is red, you stop reading the red.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions