{"record":{"id":"5f4571ea1f819175","repo":"chenhg5/cc-connect","slug":"process-exited","errorCode":null,"errorMessage":"process exited","messagePattern":"process exited","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/copilot/session.go","lineNumber":251,"sourceCode":"\t\tEnvValueMode:                   \"direct\",\n\t\tEnableConfigDiscovery:          &enableConfigDiscovery,\n\t}\n}\n\nfunc newCopilotSessionID() string {\n\tvar b [16]byte\n\tif _, err := rand.Read(b[:]); err != nil {\n\t\treturn fmt.Sprintf(\"cc-connect-%d\", time.Now().UnixNano())\n\t}\n\tb[6] = (b[6] & 0x0f) | 0x40\n\tb[8] = (b[8] & 0x3f) | 0x80\n\treturn fmt.Sprintf(\"%08x-%04x-%04x-%04x-%012x\", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16])\n}\n\nfunc (cs *copilotSession) readLoop(stderrBuf *bytes.Buffer) {\n\tdefer func() {\n\t\tcs.alive.Store(false)\n\t\tcs.rpc.cancelAll(fmt.Errorf(\"process exited\"))\n\n\t\t// Wait for process exit\n\t\tif err := cs.cmd.Wait(); err != nil {\n\t\t\tstderrMsg := strings.TrimSpace(stderrBuf.String())\n\t\t\tif stderrMsg != \"\" {\n\t\t\t\tslog.Error(\"copilotSession: process failed\", \"error\", err, \"stderr\", stderrMsg)\n\t\t\t\tevt := core.Event{Type: core.EventError, Error: fmt.Errorf(\"%s\", stderrMsg)}\n\t\t\t\tselect {\n\t\t\t\tcase cs.events <- evt:\n\t\t\t\tcase <-cs.ctx.Done():\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tclose(cs.events)\n\t\tclose(cs.done)\n\t}()\n\n\tfor {","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/copilot/session.go#L233-L269","documentation":"When the Copilot CLI child process terminates, readLoop's deferred cleanup marks the session dead and cancels every in-flight RPC with the sentinel error 'process exited'. Any caller blocked on a pending RPC (handshake, send, permission response) receives this error, indicating the transport died because the process is gone.","triggerScenarios":"readLoop's deferred func runs after the CLI's stdout closes: cs.alive.Store(false) then cs.rpc.cancelAll(fmt.Errorf(\"process exited\")); surfaces on any pending rpc.call waiter — e.g. an in-flight session.create/send — when the CLI crashes, is killed (OOM, signal), or exits voluntarily.","commonSituations":"Copilot CLI crashes on a malformed request; host OOM-kills the CLI; the process is killed by an external signal (systemd stop, user kill); CLI exits immediately due to missing binary/arg incompatibility at startup; abrupt disconnect of the controlling terminal.","solutions":["Check the log line 'copilotSession: process failed' that follows — it carries the Wait() error and the CLI's stderr, which names the real cause.","Fix the underlying CLI failure (missing binary, auth, bad flag) revealed by the stderr text, then restart the session.","Restart the session (/new or reconnect) — pending RPCs cannot recover once the process is gone.","If OOM-killed, reduce concurrency/memory pressure or move the CLI to a larger host.","If killed by systemd/launchd, raise the service memory limit or stop-timeout so the CLI is not terminated mid-request."],"exampleFix":"// before: CLI killed by systemd on stop\n# systemctl stop cc-connect  -> CLI gets SIGTERM mid-RPC -> \"process exited\"\n// after: give the service a graceful shutdown window\n# cc-connect.service\n[Service]\nTimeoutStopSec=30\nKillMode=mixed","handlingStrategy":"fallback","validationCode":"if !sessionAlive(session) {\n    session = agent.StartSession(ctx, opts)\n}","typeGuard":"func sessionAlive(s core.AgentSession) bool {\n    if a, ok := s.(interface{ IsAlive() bool }); ok {\n        return a.IsAlive()\n    }\n    return true\n}","tryCatchPattern":"for evt := range session.Events() {\n    if evt.Type == core.EventError && strings.Contains(fmt.Sprint(evt.Error), \"process exited\") {\n        slog.Error(\"copilot CLI died; restarting session\")\n        session = agent.StartSession(ctx, opts)\n    }\n}","preventionTips":["Monitor the event stream for EventError and restart the session on 'process exited'","Fix the stderr cause logged by 'copilotSession: process failed' before restarting","Raise supervisor memory limits to avoid OOM kills of the CLI","Use graceful shutdown windows so the CLI is not killed mid-RPC"],"tags":["process-crash","rpc","session-lifecycle","process-management"],"backgroundTag":"connection-refused","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}