CommandCodeAI / CommandCodeAI/command-code

Uncaught `write EOF` on Windows kills the session after a large MCP tool result

Aperta
#859 1 commento 0 reazioni 1 assegnatario Vedi su GitHub

@naymurdev ci sta già lavorando.

Dal 16/9/2026.

windows
Lingua principale
Nessun dato sulla lingua
Stelle
4k
Fork
350
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Summary

On Windows, a large MCP tool result makes the CLI die with an uncaught Error: write EOF
(WriteWrap.onWriteComplete, node:internal/stream_base_commons:87:19) and exit immediately.
No recovery: any uncaught exception is fatal by design.

Environment

  • Command Code v1.54.0 (latest on npm at the time)
  • OS: Windows (win32), binary cmdc, shell PowerShell, terminal Windows Terminal
  • Model: deepseek/deepseek-v4.1-flash (effort high)
  • MCP server involved: clickupHTTP transport with OAuth (https://mcp.clickup.com/mcp)

Steps to reproduce

  1. Configure the ClickUp MCP server (http + OAuth) and complete auth.
  2. In a session, ask for the details of a large task, so the agent issues:
{
  "tool": "mcp__clickup__clickup_get_task",
  "input": {
    "task_id": "SP-5250",
    "include": ["description", "custom_fields", "checklists", "subtasks", "attachments"]
  }
}

(note: the tool is first loaded via search_tools with select:mcp__clickup__clickup_get_task)

  1. The tool returns ~102 KB of JSON (the task has a ~50 KB markdown_description).

Observed

The tool result is received, persisted to the session transcript and spilled to
%TEMP%\commandcode\toolout\ (113,649 bytes) — and immediately after, while the loop continues
(building/sending the next turn), the CLI prints:

CRITICAL: Uncaught Exception!
ERROR  -> Error
REASON -> write EOF
STACK  -> Error: write EOF
            at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:87:19)

and the process exits (process.exit(1)). The TUI closes without warning.

Trace ID: 1ebb760a09a72cbe96dc6b03e148b0fc
Session: 98584fe6-abfb-4ff2-a888-05210eb72139
A second session crashed identically on the same payload (0138f4fb-45bc-481f-bb4d-c9c4f97a5c4d,
traceIds include several additional ids).

Expected

A failed write on a network socket should surface as a tool/network error (retry or reported error),
not as an uncaught exception that kills the whole session, especially since the payload is already
persisted on disk.

Analysis

write EOF is libuv UV_EOF on a write completion — the Windows equivalent of EPIPE: something
wrote to a stream whose peer had already closed it. It is a socket/pipe write, not a terminal write.

The CLI already has a whitelist for exactly this class of error, in dist/cli.mjs:

var zD = ["EPIPE","ECONNRESET","EOF"];
function isBenignStreamWriteError(e){
  ...
  return !!zD.some(e => r.includes(`write ${e}`)) || (t.syscall === "write" && zD.includes(n));
}
function handleStdoutError(e){ if(!isBenignStreamWriteError(e)) throw e; exitAfterModHostTeardown(0) }
function handleStderrError(e){ if(!isBenignStreamWriteError(e)) throw e }
function handleUnhandledErrors(){
  process.stdout.on("error", handleStdoutError);
  process.stderr.on("error", handleStderrError);
  process.on("unhandledRejection", ...);
  process.on("uncaughtException", ...);
}

isBenignStreamWriteError does match write EOF, but handleUnhandledErrors() attaches it
only to process.stdout / process.stderr. A write EOF emitted on any other stream — the HTTP
socket to the API/model, the MCP transport, a child pipe — is not covered, so it reaches the
uncaughtException handler and becomes fatal. If the same error occurred on stdout it would be
swallowed silently (exit(0), no banner), which confirms the failing stream is a socket and not the
TUI.

Correlation with size: the crash happens right after a ~102 KB tool result and only on this call.
Everything else about the setup looks healthy — calling the ClickUp MCP endpoint directly with the
stored token returns 200 OK in 1.4 s, connection: keep-alive, content-type: application/json,
and the OAuth access token is valid until 2036, so it is not a re-auth/refresh issue. The MCP timeout
is not involved either (default Nt = 8e4 = 80 s, the crash happened at ~17 s).

Suggested fix

Treat benign stream write errors (EPIPE / ECONNRESET / EOF) as non-fatal globally (or attach
the same guard to the network/transport streams), and/or wrap the socket write path so an aborted or
keep-alive-reused connection surfaces as a retriable request error instead of an uncaught exception.

Notes

  • No local logs existed because DEBUG was not set; I reproduced this twice so it is deterministic.
  • The full tool output survives in %TEMP%\commandcode\toolout\, and the transcript in
    ~/.commandcode/projects/<slug>/<session-id>.jsonl ends exactly at the tool_result message
    (102,727 bytes), so awaiting-the-next-step is where it dies.
  • Happy to run further instrumented reproductions (DEBUG=true, CMD_FLICKER_DEBUG=1) if useful.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.