chenhg5/cc-connect · error

pi: context cancelled while waiting for rpc ready

Error message

pi: context cancelled while waiting for rpc ready

What it means

While waiting for the pi RPC subprocess's readiness signal (rpcReady), newPiSession also selects on ctx.Done(). If the caller's context is cancelled (or its deadline expires) before pi becomes ready, the subprocess is killed and this error is returned. It is the caller-driven cancellation counterpart to the fixed 30-second timeout.

Source

Thrown at agent/pi/session.go:159

		s.extPending = make(map[string]string)
		s.extPendingRev = make(map[string]string)
		s.extMethod = make(map[string]string)

		if err := s.startRPC(resumeID); err != nil {
			cancel()
			return nil, fmt.Errorf("pi: start rpc: %w", err)
		}

		// Wait for first JSON line (indicates RPC loop is live)
		select {
		case <-s.rpcReady:
		case <-time.After(30 * time.Second):
			s.killRPC()
			cancel()
			return nil, fmt.Errorf("pi: rpc process did not become ready within 30s")
		case <-ctx.Done():
			s.killRPC()
			return nil, fmt.Errorf("pi: context cancelled while waiting for rpc ready")
		}
	} else if resumeID != "" && resumeID != core.ContinueSession {
		// JSON mode: set the session ID directly since we don't spawn a process
		// that would emit a session event.
		s.sessionID.Store(resumeID)
	}

	return s, nil
}

// ── RPC process helpers (rpc=true) ──────────────────────────

func (s *piSession) startRPC(resumeID string) error {
	args := append(append([]string{}, s.extraArgs...), "--mode", "rpc")
	if resumeID != "" {
		args = append(args, "--session-id", resumeID)
	}
	if s.model != "" {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry StartSession with a fresh, uncancelled context that has an adequate deadline (e.g. >30s to cover the probe).
  2. Check what cancelled the context: inspect ctx.Err() (DeadlineExceeded vs Canceled) in the wrapping layer and address the upstream source.
  3. If pi startup is routinely slow, raise the caller's deadline or keep a warm session pool so cancellation rarely interrupts startup.
  4. Ensure the platform/engine isn't cancelling session contexts prematurely during reconnects.

Example fix

// before
sess, err := agent.StartSession(ctxWith2sDeadline, sessionID)
// after
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
sess, err := agent.StartSession(ctx, sessionID)
Defensive patterns

Strategy: try-catch

Validate before calling

if err := ctx.Err(); err != nil {
    return fmt.Errorf("context already done before starting pi session: %w", err)
}
// prefer generous deadlines: startup + 30s probe
deadline, ok := ctx.Deadline()
if ok && time.Until(deadline) < 35*time.Second {
    log.Printf("warning: %s may be too short for pi RPC startup", deadline)
}

Try / catch

sess, err := agent.StartSession(ctx, opts)
if err != nil {
    if errors.Is(ctx.Err(), context.Canceled) {
        return fmt.Errorf("session start cancelled by caller: %w", err)
    }
    if errors.Is(ctx.Err(), context.DeadlineExceeded) {
        // retry with a fresh, longer-deadline context
        sess, err = agent.StartSession(freshCtx, opts)
    }
}

Prevention

When it happens

Trigger: StartSession called with a context that is cancelled or expires while the pi RPC process is still starting: HTTP request context ended by the client disconnecting, platform shutdown cancelling the session context, an explicit deadline shorter than pi's startup time.

Common situations: Users cancelling a chat request while the session spins up; gateway timeouts with deadlines of a few seconds while pi takes 10-20s to start; engine shutdown/Stop() cancelling in-flight StartSession calls; tests passing already-cancelled contexts.

Related errors


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