chenhg5/cc-connect · error
session is closed
Error message
session is closed
What it means
opencode's session Send stages any images, then checks an atomic `alive` flag; if the underlying opencode session process has exited or the session was closed, Send returns `session is closed` without invoking the CLI. Like the kimi adapter, a session is only usable while its process is alive, and this error marks use of a stale handle.
Source
Thrown at agent/opencode/session.go:78
if resumeID != "" && resumeID != core.ContinueSession {
s.chatID.Store(resumeID)
}
return s, nil
}
func (s *opencodeSession) Send(prompt string, messageID string, images []core.ImageAttachment, files []core.FileAttachment) error {
if len(files) > 0 {
filePaths := core.SaveFilesToDisk(s.workDir, messageID, files)
prompt = core.AppendFileRefs(prompt, filePaths)
}
prompt, imagePaths, err := s.stageImages(prompt, images)
if err != nil {
return err
}
if !s.alive.Load() {
return fmt.Errorf("session is closed")
}
s.resultSent.Store(false)
s.expectingContinue.Store(false)
chatID := s.CurrentSessionID()
isResume := chatID != ""
args := s.buildRunArgs(prompt, imagePaths, chatID)
slog.Debug("opencodeSession: launching", "resume", isResume, "args", core.RedactArgs(args))
cmd := exec.CommandContext(s.ctx, s.cmd, args...)
cmd.Dir = s.workDir
env := os.Environ()
if len(s.extraEnv) > 0 {
env = core.MergeEnv(env, s.extraEnv)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Re-acquire the live session via the engine/SessionManager instead of holding a long-lived reference; on this error, start a new session and resend.
- Investigate why the process exited: the adapter emits an EventError with stderr before dying — consume Events() to capture the cause.
- Add retry logic that distinguishes 'session is closed' (recreate session) from transient send failures (retry same session).
- Avoid calling Stop()/Close() concurrently with Send; serialize lifecycle operations.
Example fix
// before
if err := s.Send(prompt, msgID, nil, nil); err != nil {
return err
}
// after
if err := s.Send(prompt, msgID, nil, nil); err != nil {
if strings.Contains(err.Error(), "session is closed") {
ns, serr := agent.StartSession(ctx, opts)
if serr != nil {
return serr
}
return ns.Send(prompt, msgID, nil, nil)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// keep a fresh view of live sessions before sending
infos, err := agent.ListSessions(ctx)
if err == nil && !containsID(infos, s.CurrentSessionID()) {
ns, err := agent.StartSession(ctx, opts) // stale: recreate first
if err != nil { return err }
s = ns
} Type guard
func isSessionClosed(err error) bool {
return err != nil && strings.Contains(err.Error(), "session is closed")
} Try / catch
if err := s.Send(prompt, msgID, nil, nil); err != nil {
if isSessionClosed(err) {
ns, serr := agent.StartSession(ctx, opts)
if serr != nil { return serr }
return ns.Send(prompt, msgID, nil, nil)
}
return err
} Prevention
- Resolve sessions through the engine instead of storing long-lived AgentSession pointers
- Consume Events() so the stderr EventError that precedes process death is logged and acted on
- Never interleave Close()/Stop() with in-flight Sends without synchronization
- Alert on opencode CLI crash loops — repeated 'session is closed' means the process keeps dying
When it happens
Trigger: Calling Send() after: the opencode session process terminated (crash, completion, cancellation of its context); Close() already ran; the session was closed server-side and the adapter detected the exit; reusing a saved session reference across engine session switches.
Common situations: Messaging the bot after the coding session ended; the opencode CLI crashing between turns (check stderr/logs); resuming a stale session id after /new; concurrent Stop() from a timeout watchdog racing an in-flight prompt.
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
- session is closed
- session process is not running
- write stdin: %w
- iflowSession: resolve session dir: %w
- session not found: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/cc93ff579a03fc08.
Report an issue: GitHub.