{"record":{"id":"a6fdb92b6aeaf74f","repo":"chenhg5/cc-connect","slug":"s-a6fdb9","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/claudecode/session.go","lineNumber":559,"sourceCode":"\t\t}\n\t\t_ = stdout.Close()\n\t}()\n\n\treturn waitErrCh, waitDone\n}\n\nfunc (cs *claudeSession) finishReadLoop(waitErrCh <-chan error, stderrBuf *bytes.Buffer) {\n\terr := <-waitErrCh\n\n\tcs.alive.Store(false)\n\tif err != nil {\n\t\tstderrMsg := \"\"\n\t\tif stderrBuf != nil {\n\t\t\tstderrMsg = strings.TrimSpace(stderrBuf.String())\n\t\t}\n\t\tif stderrMsg != \"\" {\n\t\t\tslog.Error(\"claudeSession: process failed\", \"error\", err, \"stderr\", stderrMsg)\n\t\t\tevt := core.Event{Type: core.EventError, Error: fmt.Errorf(\"%s\", stderrMsg)}\n\t\t\tselect {\n\t\t\tcase cs.events <- evt:\n\t\t\tcase <-cs.ctx.Done():\n\t\t\t\t// INVARIANT: readLoop must close cs.events and cs.done exactly once\n\t\t\t\t// on every termination path. Callers (engine event loop) rely on\n\t\t\t\t// these closures to observe session end.\n\t\t\t}\n\t\t}\n\t}\n\tclose(cs.events)\n\tclose(cs.done)\n}\n\nfunc (cs *claudeSession) handleReadLoopScanErr(err error, waitDone <-chan struct{}) {\n\tif err == nil {\n\t\treturn\n\t}\n","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/claudecode/session.go#L541-L577","documentation":"When the claude process terminates with an error, finishReadLoop extracts whatever the CLI wrote to stderr and relays it verbatim (fmt.Errorf(\"%s\", stderrMsg)) as a core.EventError on the session event channel. This is the surface through which Claude Code's own failure output (bad flag, auth failure, version mismatch) reaches the engine/user.","triggerScenarios":"The claude process exits non-zero or the scanner loop ends with an error while stderrBuf holds output — e.g. claude was invoked with an unsupported flag (e.g. after a CLI upgrade removed --replay), the API key/login expired, or the CLI crashed at startup.","commonSituations":"Expired Claude subscription/login requiring `claude login`; CLI version change breaking a flag; invalid model name in config; network/API outage causing the CLI to abort with a message on stderr.","solutions":["Read the stderr text in the event message — it contains the CLI's own diagnosis and dictates the fix","Run `claude --version` and `claude doctor`; upgrade or pin the CLI to a version compatible with cc-connect's flags","Re-authenticate: run `claude login` (or fix ANTHROPIC_API_KEY in providerEnv) as the daemon user","Reproduce manually with the same args/model from config to see the stderr directly"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// preflight the CLI before creating sessions\nfunc claudeHealthy(bin string) error {\n    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n    defer cancel()\n    out, err := exec.CommandContext(ctx, bin, \"--version\").CombinedOutput()\n    if err != nil {\n        return fmt.Errorf(\"claude CLI check failed: %v: %s\", err, out)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"go func() {\n    for evt := range sess.Events() {\n        if evt.Type == core.EventError {\n            // evt.Error wraps raw CLI stderr — show it and recreate session\n            notifyUser(\"claude session failed: \" + evt.Error.Error())\n            sess = recreateSession()\n        }\n    }\n}()","preventionTips":["Keep the Claude CLI authenticated (`claude login` as the daemon user; check expiry)","Pin/verify CLI version compatibility after upgrades — removed flags fail here","Validate model names in config against the installed CLI","Alert on EventError events rather than silently ignoring them"],"tags":["process-lifecycle","stderr","cli","event-error"],"backgroundTag":"upstream-api-error","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"}