Symptom
When an ACP agent process exits during startup, the renderer shows only:
Failed to load chat. ACP connection closed
Nothing tells the user (or the logs) why the agent died, even though the agent printed a precise, actionable error on stderr before exiting.
Incident (2026-08-06)
Launching an OpenCode conversation on a ProtoRTS worktree failed with the message above. Actual cause: the repo carried an invalid opencode.json (an extra mcp.servers nesting — opencode's schema has none), so every opencode acp spawn exited immediately with:
Error: Configuration is invalid at .../opencode.json
↳ Expected { "type": "local", ... } | { "type": "remote", ... }, got {...} mcp.servers
That message never surfaced anywhere. The app log only had:
error: "ACP connection closed" msg: "createAcpAgentConnection: initialize failed"
error: "[object Object]" msg: "AcpConnectionSource: provisioning failed"
Diagnosing it required querying the app DB for the workspace path and replaying the JSON-RPC handshake by hand.
Root causes
- stderr is dropped.
packages/runtime/src/acp-agents/connection/acp-agent-connection.ts (~line 77): agent stderr is logged at debug only and never attached to the error, so in a packaged build it vanishes.
- Opaque error on early exit. When the process dies before
initialize completes, the error that wins the race and reaches the renderer's AcpStartError is the SDK's generic "ACP connection closed" — no exit code, no stderr. (failClosedBeforeReady does build a message with the exit code, but it can lose the race against the SDK connection error, and it still has no stderr either way.)
- Broken log serialization.
packages/runtime/src/acp-agents/connection/source.ts:71: String(error) on an AcpConnectionError plain object prints [object Object].
Proposed fix
- Keep a small bounded ring buffer of the agent's recent stderr in
createAcpAgentConnection.
- On close-before-ready (and on initialize failure generally), build the
InitializeFailedError from exit code + last stderr lines, and make sure that detail propagates through AcpConnectionSource → RPC → renderer AcpStartError, so the chat panel error state can show the real reason.
- Serialize the error properly in the
provisioning failed log line (it is a {type, ...} object, not an Error).
Repro
- In any project, create an
opencode.json with the invalid nesting: {"mcp": {"servers": {"x": {"type": "local", "command": ["true"]}}}}
- Open an OpenCode (ACP) conversation on a task in that project.
- Observe "Failed to load chat. ACP connection closed" with no mention of the config error that opencode printed on stderr.
Symptom
When an ACP agent process exits during startup, the renderer shows only:
Nothing tells the user (or the logs) why the agent died, even though the agent printed a precise, actionable error on stderr before exiting.
Incident (2026-08-06)
Launching an OpenCode conversation on a ProtoRTS worktree failed with the message above. Actual cause: the repo carried an invalid
opencode.json(an extramcp.serversnesting — opencode's schema has none), so everyopencode acpspawn exited immediately with:That message never surfaced anywhere. The app log only had:
Diagnosing it required querying the app DB for the workspace path and replaying the JSON-RPC handshake by hand.
Root causes
packages/runtime/src/acp-agents/connection/acp-agent-connection.ts(~line 77): agent stderr is logged atdebugonly and never attached to the error, so in a packaged build it vanishes.initializecompletes, the error that wins the race and reaches the renderer'sAcpStartErroris the SDK's generic "ACP connection closed" — no exit code, no stderr. (failClosedBeforeReadydoes build a message with the exit code, but it can lose the race against the SDK connection error, and it still has no stderr either way.)packages/runtime/src/acp-agents/connection/source.ts:71:String(error)on anAcpConnectionErrorplain object prints[object Object].Proposed fix
createAcpAgentConnection.InitializeFailedErrorfrom exit code + last stderr lines, and make sure that detail propagates throughAcpConnectionSource→ RPC → rendererAcpStartError, so the chat panel error state can show the real reason.provisioning failedlog line (it is a{type, ...}object, not anError).Repro
opencode.jsonwith the invalid nesting:{"mcp": {"servers": {"x": {"type": "local", "command": ["true"]}}}}