chenhg5/cc-connect · warning

agent session ended

Error message

agent session ended

What it means

Not a returned error but a reason string passed to notifyDroppedQueuedMessages when an interactive session's agent session is missing or no longer Alive() at drain time. All queued user messages for that session are dropped and the user is notified.

Source

Thrown at core/engine.go:3289

// drainOrphanedQueue is called when a message was queued but the drain loop
// has already exited. It processes all pending messages in the state, similar
// to the drain loop in processInteractiveMessageWith but as a standalone
// goroutine.
func (e *Engine) drainOrphanedQueue(session *Session, sessions *SessionManager, interactiveKey string, agent Agent, workspaceDir string) {
	unlocked := false
	defer func() {
		if !unlocked {
			session.Unlock()
		}
	}()

	e.interactiveMu.Lock()
	state, hasState := e.interactiveStates[interactiveKey]
	e.interactiveMu.Unlock()

	if !hasState || state == nil || state.agentSession == nil || !state.agentSession.Alive() {
		if hasState && state != nil {
			e.notifyDroppedQueuedMessages(state, fmt.Errorf("agent session ended"))
		}
		return
	}

	// Stop unsolicited reader before draining — drainPendingMessages reads
	// from Events() and we must not have concurrent readers.
	e.stopUnsolicitedReader(state)

	unlocked = e.drainPendingMessages(state, session, sessions, interactiveKey)

	// Restart unsolicited reader if the session is still alive and clean.
	state.mu.Lock()
	alive := state.agentSession != nil && state.agentSession.Alive() && !state.stopped && !state.eventsNeedResync
	state.mu.Unlock()
	if alive {
		e.startUnsolicitedReader(state, session, sessions, interactiveKey, workspaceDir)
	}
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check agent process logs for the crash/exit cause
  2. Recreate the session (/new or send a fresh message) to spawn a new agent session
  3. Reduce queue time by sending messages when the session is active
  4. Monitor agent health to detect premature exits
Defensive patterns

Strategy: type-guard

Validate before calling

if state == nil || state.agentSession == nil || !state.agentSession.Alive() { /* recreate session before enqueueing */ }

Type guard

alive := state != nil && state.agentSession != nil && state.agentSession.Alive()

Try / catch

engine.OnQueuedMessagesDropped(func(key string, reason error) { user.Notify("session ended; please resend") })

Prevention

When it happens

Trigger: Drain runs after the agent process exited/crashed or state.agentSession is nil; interactive state exists but its session is dead.

Common situations: Agent CLI crashed or was killed externally during a long prompt; session timed out and closed before queued messages were flushed.

Related errors


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