chenhg5/cc-connect · error

session process is not running

Error message

session process is not running

What it means

Send refuses to write to the claude process when cs.alive is false, returning 'session process is not running'. The alive flag is cleared when the process exits (readLoop/Close), so this error means the message arrived for a session whose process has already died or been closed.

Source

Thrown at agent/claudecode/session.go:981

	if toolName == "AskUserQuestion" {
		evt.Questions = parseUserQuestions(input)
	}

	select {
	case cs.events <- evt:
	case <-cs.ctx.Done():
		return
	}
}

// Send writes a user message (with optional images and files) to the Claude process stdin.
// Images are sent as base64 in the multimodal content array.
// Files are saved to local temp files and referenced in the text prompt
// so Claude Code can read them with its built-in tools.
func (cs *claudeSession) Send(prompt string, messageID string, images []core.ImageAttachment, files []core.FileAttachment) error {
	if !cs.alive.Load() {
		return fmt.Errorf("session process is not running")
	}

	if len(images) == 0 && len(files) == 0 {
		return cs.writeJSON(map[string]any{
			"type":    "user",
			"message": map[string]any{"role": "user", "content": prompt},
		})
	}

	attachDir := filepath.Join(cs.workDir, ".cc-connect", "attachments")
	if err := os.MkdirAll(attachDir, 0o755); err != nil {
		slog.Warn("claudeSession: mkdir attachments failed", "error", err, "path", attachDir)
	}

	var parts []map[string]any
	var savedPaths []string

	// Save and encode images

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Start a new session via StartSession and re-send the prompt — the old session is unrecoverable
  2. Check the session's event feed for the earlier EventError (e.g. stderr from the CLI) explaining why it died
  3. If this happens often, add engine-level auto-restart: on EventError/Send failure, recreate the session for the same conversation
  4. Upgrade/pin the Claude CLI if crashes are the root cause of frequent dead sessions
Defensive patterns

Strategy: validation

Validate before calling

// gate sends on session liveness and recreate when dead
func safeSend(s core.AgentSession, isAlive func() bool, prompt string) error {
    if !isAlive() {
        return errors.New("session dead: recreate with StartSession before sending")
    }
    return s.Send(prompt, "", nil, nil)
}

Try / catch

if err := sess.Send(prompt, msgID, nil, nil); err != nil {
    if strings.Contains(err.Error(), "not running") {
        sess, err = agent.StartSession(ctx, lastPrompt)
        if err == nil {
            err = sess.Send(prompt, msgID, nil, nil)
        }
    }
}

Prevention

When it happens

Trigger: Calling Send on a claudeSession after: the claude process exited (crash, stderr failure relayed as EventError), Close() was called, or the engine considered the session live but the process died concurrently between the event feed and the send.

Common situations: User sends a message in the chat platform while the CLI crashed seconds earlier; cron/timer job targeting a stale session; engine raced process exit; daemon resumed with sessions that never survived restart.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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