Skip to content

bug(acp): AcpFileSystemService.normalizeFileSystemError misses structured ENOENT codes and common not-found phrasings #26448

@frozename

Description

@frozename

What happened?

When gemini runs as an ACP agent and the host returns a file-system error from a delegated readTextFile call, AcpFileSystemService.normalizeFileSystemError (packages/cli/src/acp/acpFileSystemService.ts) decides whether the error means "file not found" by substring-matching the human-readable message against four exact phrases:

errorMessage.includes('Resource not found') ||
errorMessage.includes('ENOENT') ||
errorMessage.includes('does not exist') ||
errorMessage.includes('No such file')

The structured JSON-RPC code field on the error response (-32002 = RESOURCE_NOT_FOUND per the ACP spec) is ignored. Common phrasings produced by ACP hosts that don't match any of those four substrings — for example not_found: file not found, no such file or directory, or file_not_found — are classified as generic file-system errors instead of ENOENT.

The user-visible symptom: write_file on a new path internally calls readTextFile first to check whether the file exists. When the read returns a not-found error that fails the substring check, the write tool sees a generic FS error rather than the expected ENOENT, treats the path as "exists but unreadable", and either retries or reports an opaque failure. From outside, the agent reasoning loop appears to hallucinate success after several retries because no write actually lands.

This was discovered wiring gemini --experimental-acp into a custom ACP host. When the host's read errors carried message not_found: file not found and code -32002, every write_file call on a non-existent path silently failed (multi-minute hangs, watchdog restarts). Reformatting the host's error message to include the literal substring ENOENT made every write start succeeding immediately — confirming the substring matcher is the load-bearing path.

#14190 attempted a similar fix earlier but was closed un-merged on 2026-01-24. #17588 was closed on the assumption that #14190 had landed, so the symptom is still live in 0.40.1.

What did you expect to happen?

normalizeFileSystemError should:

  1. Inspect the JSON-RPC code field first and return ENOENT for -32002 (RESOURCE_NOT_FOUND) regardless of message phrasing.
  2. Recognize broader human-readable not-found phrasings (no such file, file_not_found, not_found, cannot find) so that hosts using non-canonical wording still produce ENOENT downstream.

Client information

Client Information
gemini --version: 0.40.1
Platform:        darwin arm64 (Darwin 25.4.0)
Mode:            --experimental-acp

(Discovered while running gemini --experimental-acp against a custom ACP host implementing fs.readTextFile / fs.writeTextFile delegation. The bug reproduces against any host whose not-found error message doesn't contain one of the four hardcoded substrings.)

Login information

Google account.

Anything else we need to know?

Metadata

Metadata

Assignees

No one assigned

    Labels

    status/need-triageIssues that need to be triaged by the triage automation.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions