Skip to content

[Bug] buzz-acp drops JSON-RPC error.data, hiding actionable failures — CLI/adapter version mismatch surfaces only as "-32603 Internal error" retry loops #2422

Description

@JAFairweather

Summary

When the Claude CLI on the user's machine is incompatible with the bundled claude-agent-acp adapter (in my case: CLI 2.0.25 does not support the --tools flag that adapter 0.60.0 passes), every session/new fails instantly. The adapter reports the precise cause in the JSON-RPC error's data field:

{"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"Internal error",
 "data":{"details":"Claude Code process exited with code 1. stderr: error: unknown option '--tools'"}}}

buzz-acp discards error.data when constructing AcpError::AgentError (only code and message survive — crates/buzz-acp/src/acp.rs:111-121), so the harness log and the user-facing channel notice both reduce to:

⚠️ I couldn't process the last request after multiple retries (Agent reported error (code -32603): Internal error). Please re-send if it's still needed.

Because AgentError is classified as an application-class error ("session is healthy — don't invalidate", crates/buzz-acp/src/pool.rs:2169; no respawn, handle_prompt_result in crates/buzz-acp/src/lib.rs), the harness retries the hopeless spawn with backoff (10 attempts, 5s→300s) for every incoming message, dead-letters each batch, and never recovers or escalates. All managed agents on the machine (three in my case) wedge identically and indefinitely.

The failure is deterministic and permanent, yet the user experience is an unexplained "Internal error" that looks transient. In my case it presented as "my agents died when I hit my Claude usage limit and never came back" — the actual trigger was that fresh CLI spawns resolved a different (older) claude binary than the still-running processes from the previous day, so everything kept working until the app restarted.

Confirmed: upgrading the CLI (npm install -g @anthropic-ai/claude-code@latest) and restarting the agents fully restores them — the version mismatch was the sole cause.

Environment

  • Packaged macOS desktop build (xyz.block.buzz.app), three managed Claude agents
  • Bundled adapter: @agentclientprotocol/claude-agent-acp 0.60.0 (Buzz node-tools, bundled node v24.11.0)
  • User CLI: Claude Code 2.0.25 (npm global under nvm node v22.16.0) — works fine standalone (claude -p succeeds); does not support --tools
  • Code refs against main @ aaf48fc

Reproduction

  1. Install a Claude Code CLI version that predates the --tools flag (e.g. 2.0.25) as the claude the login shell resolves.
  2. Run any managed Claude agent and mention it in a channel.
  3. Harness log shows only agent_returned (application error — pipe intact) … error=Agent reported error (code -32603): Internal error × 10 with backoff, then dead-lettering batch after 10 retries.
  4. Drive the adapter directly with an ACP handshake (initialize → session/new) to see the real error in error.data.details (probe transcript above).

Root causes

  1. Diagnostic loss: acp.rs agent_error_from_json keeps code + message, drops data. Per JSON-RPC 2.0, data is exactly where servers put the useful detail; the claude adapter uses it for the subprocess's stderr.
  2. No escalation for deterministic failures: application-class AgentError never invalidates the session, never respawns, never trips the circuit breaker, and never varies its handling no matter how many consecutive identical failures occur — so a permanent config problem is retried forever as if transient.
  3. No compatibility preflight: desktop discovery verifies the underlying CLI exists (and probes auth) but not that its version is compatible with the bundled adapter, so a stale/shadowed claude (nvm per-node-version globals make this easy) fails only at session-spawn time, with the message from (1).

Suggested fixes

  • Append error.data (stringified, truncated) to AcpError::AgentError's Display and to the turn_error observer payload — one-line-ish change that would have made this self-diagnosing.
  • Track consecutive AgentErrors per agent; after N identical failures, invalidate the session, then respawn the slot, then trip SlotCircuit — and surface a distinct user-facing notice ("agent failed N times with:
    Details") instead of the generic retry text.
  • At spawn (or in discovery), run claude --version against the resolved CLAUDE_CODE_EXECUTABLE and check it against the bundled adapter's minimum supported version; badge the agent as misconfigured instead of letting it enter the retry loop.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions