chenhg5/cc-connect · critical

pi: rpc process did not become ready within 30s

Error message

pi: rpc process did not become ready within 30s

What it means

After spawning the pi RPC subprocess, newPiSession waits on s.rpcReady for the first JSON line proving the RPC loop is live. If nothing arrives within 30 seconds, the process is killed and this timeout error is returned. It means pi started but never produced its readiness handshake.

Source

Thrown at agent/pi/session.go:156

	if rpc {
		s.rpcReady = make(chan struct{})
		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 != "" {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Run `pi` manually in a terminal as the same user — if it prompts for login/setup, complete that first so startup is non-interactive.
  2. Check s.stderrBuf (captured in the session) or run pi with debug logging to see what it printed while hanging.
  3. Confirm pi version compatibility with this adapter; downgrade/upgrade pi if the startup protocol changed.
  4. If starts are merely slow, increase the 30s probe timeout in agent/pi/session.go (or warm the machine) — otherwise treat hangs as auth/config problems.

Example fix

// before: pi prompts on first run, daemon hangs
// after: pre-authenticate once interactively
$ pi --login   # or run pi once and complete setup
$ cc-connect   # now RPC start emits the ready line immediately
Defensive patterns

Strategy: try-catch

Validate before calling

out, err := exec.Command(cliPath, "--version").CombinedOutput()
if err != nil {
    return fmt.Errorf("pi CLI not runnable: %w (out: %s)", err, out)
}
// also confirm non-interactive startup: a pi that blocks on login will hang the RPC probe

Try / catch

sess, err := agent.StartSession(ctx, opts)
if err != nil && strings.Contains(err.Error(), "did not become ready within 30s") {
    log.Printf("pi RPC never signalled ready; check pi auth/first-run setup and stderr capture")
    return fmt.Errorf("pi startup hung; complete `pi` first-run login as the service user: %w", err)
}

Prevention

When it happens

Trigger: StartSession in RPC mode when the pi binary hangs at startup (waiting for auth/login, prompting interactively on stdin/stderr), is a wrong/stub binary that never speaks the JSON-RPC protocol, blocks on network access, or is so slow to start that 30s elapses.

Common situations: pi waiting for interactive login/API-key setup on first run; very slow cold start on loaded machines or network filesystems; a pi version that changed its startup protocol so the expected first JSON line never comes; firewalls blocking pi's model-provider endpoints.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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