github/copilot-sdk · critical
CLI process exited
Error message
CLI process exited: %w
What it means
The no-stderr variant of the process-death error: the CLI process Wait() returned an error but nothing was captured on stderr, so the client reports only 'CLI process exited: <waitErr>'. The wrapped wait error (exit status) is the only diagnostic available.
Solutions
- Decode the wrapped exit status: 137/SIGKILL usually means OOM — reduce workload or increase memory.
- Check OS logs (dmesg, journalctl) for kill events around the crash time.
- Enable the CLI's own logging (file-based) since stderr was empty.
- Add restart-on-death logic around the client lifecycle.
Defensive patterns
Strategy: retry
Try / catch
_, err := client.RPC.Call(ctx, "method", args)
if err != nil {
var pe *os.SyscallError
if strings.Contains(err.Error(), "CLI process exited") {
// empty stderr: check wrapped exit status / dmesg for signal kills
log.Errorf("CLI died silently: %v", err)
}
return err
} Prevention
- Decode the wrapped exit status: 137/SIGKILL implies OOM or external kill.
- Check dmesg/journalctl for silent kill events.
- Configure the CLI to log to a file so crashes leave a trace even without stderr.
- Add restart-on-death supervision around the client.
When it happens
Trigger: The CLI process exits with a non-zero status while producing no stderr output — e.g. killed by a signal, OOM-killed, or exiting via os.Exit with a non-zero code.
Common situations: OOM killer terminating the process (exit 137/SIGKILL), external scripts or supervisors killing it, silent fatal exits from the CLI binary.
Related errors
- CLI process exited: \nstderr
- CLI process exited unexpectedly. stderr
- CLI process exited unexpectedly
- An in-process FFI runtime library is already loaded from
- CLI process exited unexpectedly.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/7a57c301dee38856.
Report an issue: GitHub.
Appendix: source
Thrown at go/client.go:2408
// they see the final processError value.
func (c *Client) monitorProcess() {
done := make(chan struct{})
c.processDone = done
proc := c.process
c.osProcess.Store(proc.Process)
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
}View on GitHub (pinned to cd8cf15dc3)