{"record":{"id":"f973ec0755bcb93c","repo":"chenhg5/cc-connect","slug":"pi-s-w","errorCode":null,"errorMessage":"pi: %s: %w","messagePattern":"pi: (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/pi/session.go","lineNumber":419,"sourceCode":"\tscanner := bufio.NewScanner(stdout)\n\tscanner.Buffer(make([]byte, 0, 64*1024), 10*1024*1024)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tvar raw map[string]any\n\t\tif err := json.Unmarshal([]byte(line), &raw); err != nil {\n\t\t\tslog.Debug(\"piSession: non-JSON line\", \"line\", truncStr(line, 100))\n\t\t\tcontinue\n\t\t}\n\t\ts.handleEvent(raw)\n\t}\n\n\terr = cmd.Wait()\n\tif err != nil {\n\t\tslog.Error(\"piSession: process error\", \"cmd\", s.cmd, \"error\", err, \"stderr\", stderrBuf.String())\n\t\tevt := core.Event{Type: core.EventError, Error: fmt.Errorf(\"pi: %s: %w\", strings.TrimSpace(stderrBuf.String()), err)}\n\t\tselect {\n\t\tcase s.events <- evt:\n\t\tcase <-s.ctx.Done():\n\t\t}\n\t}\n\n\t// Signal turn completion. Flush a deferred terminal error first in\n\t// case the process exited without a final non-retry agent_end (the\n\t// agent_end handler normally flushes pendingErr already).\n\tif s.pendingErr != \"\" {\n\t\terrEvt := core.Event{Type: core.EventError, Error: fmt.Errorf(\"%s\", s.pendingErr)}\n\t\ts.pendingErr = \"\"\n\t\tselect {\n\t\tcase s.events <- errEvt:\n\t\tcase <-s.ctx.Done():\n\t\t}\n\t}\n\tsid := s.CurrentSessionID()","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/pi/session.go#L401-L437","documentation":"agent/pi/session.go:419 — after the one-shot JSON-mode pi process finishes, sendJSON calls cmd.Wait(); if the exit status is non-zero it emits core.Event{Type:EventError, Error:\"pi: <trimmed stderr>: <wait err>\"} on the events channel (Send itself still returns nil — delivery of the error is via the event stream). This means pi ran but failed during the turn: provider errors, panics, or bad arguments.","triggerScenarios":"sendJSON (via Send, non-rpc mode) when the pi one-shot process exits non-zero: (1) provider/API failure inside pi (quota, auth, network); (2) pi panics mid-turn; (3) invalid flags produced by buildJSONArgs (bad session id, model, thinking value); (4) context cancellation killing the process.","commonSituations":"Expired or missing provider API key; rate limiting or provider outage; a huge prompt exceeding provider limits; pi crashing on malformed session state resumed via CurrentSessionID; signal/timeout cancellation (CommandContext).","solutions":["Read the stderr text after \"pi: \" in the event to identify pi's own failure and fix it (credentials, quota, flags).","Verify provider API keys are valid and set in the daemon environment.","Retry the message; transient provider/network errors often succeed on retry.","If it's a pi bug (panic trace), upgrade pi; if flags are the cause, correct model/thinking/session settings in config."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func piWaitErrorEvent(evt core.Event) (stderr string, err error, ok bool) {\n    if evt.Type != core.EventError || evt.Error == nil {\n        return \"\", nil, false\n    }\n    s := evt.Error.Error()\n    if rest, found := strings.CutPrefix(s, \"pi: \"); found && strings.Contains(rest, \": \") {\n        parts := strings.SplitN(rest, \": \", 2)\n        return parts[0], evt.Error, true\n    }\n    return \"\", nil, false\n}","tryCatchPattern":"for evt := range session.Events() {\n    if stderr, err, ok := piWaitErrorEvent(evt); ok {\n        slog.Error(\"pi json turn failed\", \"stderr\", stderr, \"err\", err)\n        if isTransient(err) { retryWithBackoff() } else { notifyUser(stderr) }\n    }\n}","preventionTips":["Validate provider API keys and quotas before long turns.","Keep prompts within provider limits; offload large content to files.","Retry transient provider failures with backoff.","Upgrade pi when panics appear in stderr; pin a known-good version."],"tags":["process-exit","nonzero-exit","stderr","go","agent-pi"],"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"}