chenhg5/cc-connect · error
write body: %w
Error message
write body: %w
What it means
After the header was written successfully, writing the JSON-RPC message body bytes to the copilot process's stdin pipe failed. Like the header write failure, this indicates the child process's stdin is closed or broken — typically the copilot process died between the header and body write or mid-request.
Source
Thrown at agent/copilot/jsonrpc.go:73
return &lspWriter{w: w}
}
func (lw *lspWriter) writeMessage(v any) error {
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("marshal: %w", err)
}
header := fmt.Sprintf("Content-Length: %d\r\n\r\n", len(data))
lw.mu.Lock()
defer lw.mu.Unlock()
if _, err := io.WriteString(lw.w, header); err != nil {
return fmt.Errorf("write header: %w", err)
}
if _, err := lw.w.Write(data); err != nil {
return fmt.Errorf("write body: %w", err)
}
return nil
}
// lspReader reads Content-Length framed JSON-RPC messages.
type lspReader struct {
reader *bufio.Reader
}
func newLSPReader(r io.Reader) *lspReader {
return &lspReader{reader: bufio.NewReaderSize(r, 64*1024)}
}
// readMessage reads one Content-Length framed message and returns the raw JSON body.
func (lr *lspReader) readMessage() ([]byte, error) {
contentLength := -1
for {
line, err := lr.reader.ReadString('\n')View on GitHub (pinned to 4000b2338a)
Solutions
- Capture copilot stderr (replace io.Discard) to find why the process died
- Retry the operation on a freshly created probe session
- Check message size; ensure the reader goroutine is draining stdout so the pipe does not block
- Verify ctx timeouts are generous enough for the RPC being sent
Example fix
// before
if _, err := lw.w.Write(data); err != nil {
return fmt.Errorf("write body: %w", err)
}
// after
if _, err := lw.w.Write(data); err != nil {
return fmt.Errorf("write body (len=%d): %w", len(data), err)
} // extra context for diagnosing dead-process writes Defensive patterns
Strategy: retry
Validate before calling
// preflight liveness + reasonable payload size
if closed := func() bool { select { case <-done: return true; default: return false } }(); closed {
return errors.New("probe process exited")
}
if len(payload) > 1<<20 { return errors.New("rpc payload unusually large") } Try / catch
if err := rpc.call(...); err != nil && strings.Contains(err.Error(), "write body") {
slog.Warn("rpc write failed mid-message; process likely died", "err", err)
// recreate session and retry
} Prevention
- Ensure the stdout reader goroutine always drains the pipe to avoid writer blocking
- Capture child stderr to diagnose process death
- Bound request payload sizes
When it happens
Trigger: call/notify/writeResponse/writeError issuing lw.w.Write(data) on a dead copilot process's stdin pipe; large messages hitting a full pipe buffer with a dead reader.
Common situations: Copilot CLI crash under memory pressure; context timeout killing the process during a large request write; race between process teardown and a pending RPC.
Related errors
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/0234f5bf6bcdd5c0.
Report an issue: GitHub.