github/copilot-sdk · critical
CLI process exited unexpectedly
Error message
CLI process exited unexpectedly
What it means
The CLI subprocess terminated without the wait error indicating a normal exit, so the monitor goroutine records processError = "CLI process exited unexpectedly", optionally with captured stderr. This error is surfaced through processErrorPtr to the JSON-RPC client and to callers awaiting the process result.
Solutions
- Read the stderr attached to the error for the underlying cause
- Check dmesg/journal for OOM or signal kills and raise limits if needed
- Ensure the runtime binary matches the SDK version; reinstall/upgrade if mismatched
- Handle the processDone/processError channel in your app to restart the client gracefully
Defensive patterns
Strategy: try-catch
Try / catch
select {
case <-client.ProcessDone():
if err := *client.ProcessError(); err != nil && strings.Contains(err.Error(), "exited unexpectedly") {
log.Errorf("CLI crashed: %v", err)
// restart client with backoff
}
case <-ctx.Done():
} Prevention
- Monitor processDone/processError and implement automatic restart with backoff
- Capture and persist stderr for post-mortem
- Match runtime and SDK versions; watch for OOM/signals in logs
When it happens
Trigger: The CLI process crashes (non-zero, unexpected exit) while the client is running; wait() returns without a recognized exit-status error and stderr may or may not be available.
Common situations: Runtime crashes mid-session; OOM kills; signal termination (SIGKILL from supervisors); corrupt or incompatible runtime binaries; underlying native library faults in runtime.node.
Related errors
- CLI process exited unexpectedly. stderr
- CLI server process exited before reporting port
- failed to gracefully shut down runtime
- failed to create stdin pipe
- failed to create stdout pipe
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/d13ea1fe4b737b14.
Report an issue: GitHub.
Appendix: source
Thrown at go/client.go:2414
var processError error
c.processErrorPtr = &processError
go func() {
waitErr := proc.Wait()
var stderrOutput string
if buf, ok := proc.Stderr.(*truncbuffer.TruncBuffer); ok {
stderrOutput = strings.TrimSpace(buf.String())
}
if waitErr != nil {
if stderrOutput != "" {
processError = fmt.Errorf("CLI process exited: %w\nstderr: %s", waitErr, stderrOutput)
} else {
processError = fmt.Errorf("CLI process exited: %w", waitErr)
}
} else {
if stderrOutput != "" {
processError = fmt.Errorf("CLI process exited unexpectedly\nstderr: %s", stderrOutput)
} else {
processError = errors.New("CLI process exited unexpectedly")
}
}
close(done)
}()
}
// connectToServer establishes a connection to the server.
func (c *Client) connectToServer(ctx context.Context) error {
if c.useStdio || c.useInProcess {
// Already connected: stdio in startCLIServer, FFI streams in startInProcess.
return nil
}
// Connect via TCP
return c.connectViaTCP(ctx)
}
// connectViaTCP connects to the CLI server via TCP socket.View on GitHub (pinned to cd8cf15dc3)