chenhg5/cc-connect · error

%s

Error message

%s

What it means

agent/pi/session.go:430 — after a JSON-mode turn completes, sendJSON flushes any deferred terminal error stored in s.pendingErr as core.Event{Type:EventError, Error:fmt.Errorf("%s", s.pendingErr)}. pendingErr is set by handleEvent (e.g. a non-retryable agent error that didn't end with a failed agent_end); this flush covers the case where the process exited without a final agent_end to flush it normally.

Source

Thrown at agent/pi/session.go:430

		}
		s.handleEvent(raw)
	}

	err = cmd.Wait()
	if err != nil {
		slog.Error("piSession: process error", "cmd", s.cmd, "error", err, "stderr", stderrBuf.String())
		evt := core.Event{Type: core.EventError, Error: fmt.Errorf("pi: %s: %w", strings.TrimSpace(stderrBuf.String()), err)}
		select {
		case s.events <- evt:
		case <-s.ctx.Done():
		}
	}

	// Signal turn completion. Flush a deferred terminal error first in
	// case the process exited without a final non-retry agent_end (the
	// agent_end handler normally flushes pendingErr already).
	if s.pendingErr != "" {
		errEvt := core.Event{Type: core.EventError, Error: fmt.Errorf("%s", s.pendingErr)}
		s.pendingErr = ""
		select {
		case s.events <- errEvt:
		case <-s.ctx.Done():
		}
	}
	sid := s.CurrentSessionID()
	evt := core.Event{Type: core.EventResult, SessionID: sid, Done: true}
	select {
	case s.events <- evt:
	case <-s.ctx.Done():
	}

	return nil
}

// writeRPCCommand marshals cmd as a single JSONL line and writes it to the
// RPC process's stdin under rpcStdinMu. Used by both sendRPC (for "prompt"

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the pendingErr text in the event — it is pi's terminal error message; address what it describes (auth, quota, prompt size).
  2. Retry the prompt if the cause was transient (rate limit, network).
  3. Shorten the prompt or move large content into on-disk files referenced by path rather than inlined.
  4. Check pi logs/version if the message indicates an internal pi error and upgrade.
Defensive patterns

Strategy: fallback

Type guard

func isPendingErrFlush(evt core.Event) bool {
    return evt.Type == core.EventError && evt.Error != nil &&
        !strings.HasPrefix(evt.Error.Error(), "pi: ") &&
        !strings.HasPrefix(evt.Error.Error(), "read stdout:")
}

Try / catch

sawResult := false
for evt := range session.Events() {
    if evt.Type == core.EventResult && evt.Done { sawResult = true }
    if evt.Type == core.EventError && evt.Error != nil {
        slog.Warn("pi terminal agent error", "msg", evt.Error.Error())
    }
}
if !sawResult { // turn ended via pendingErr flush, not agent_end
    offerRetryToUser()
}

Prevention

When it happens

Trigger: sendJSON (via Send, non-rpc mode) when handleEvent recorded s.pendingErr during the turn: (1) pi reported a fatal, non-retryable agent error event; (2) the process exited before emitting a terminal agent_end that would normally clear it; (3) a provider refused the request with a terminal status pi surfaced as pending error text.

Common situations: Provider auth/quota failures mid-turn; pi aborting on an invalid tool call; context-window overflow errors from the model; prompt rejected by the provider (e.g. oversized inlined content).

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/130fcb4cc803907e. Report an issue: GitHub.