chenhg5/cc-connect · warning
iflow session is busy
Error message
iflow session is busy
What it means
iflowSession.Send returns this when a turn is already active: `turnActive.CompareAndSwap(false, true)` failed because a previous prompt is still being processed. iflow sessions process one turn at a time, so concurrent Send calls are rejected.
Source
Thrown at agent/iflow/session.go:133
s.sentOnce.Store(true)
}
return s, nil
}
func (s *iflowSession) Send(prompt string, messageID string, images []core.ImageAttachment, files []core.FileAttachment) error {
if len(images) > 0 {
slog.Warn("iflowSession: images are not supported, ignoring")
}
if len(files) > 0 {
filePaths := core.SaveFilesToDisk(s.workDir, messageID, files)
prompt = core.AppendFileRefs(prompt, filePaths)
}
if !s.alive.Load() {
return fmt.Errorf("session is closed")
}
if !s.turnActive.CompareAndSwap(false, true) {
return fmt.Errorf("iflow session is busy")
}
turnCtx, turnCancel := context.WithCancel(s.ctx)
turn := &iflowTurn{
cancel: turnCancel,
startedAt: time.Now(),
mode: s.mode,
pendingTimeout: s.pendingToolTimeout(),
processDone: make(chan struct{}),
pendingToolIDs: make(map[string]struct{}),
pendingTools: make(map[string]iflowToolUse),
seenToolIDs: make(map[string]struct{}),
doneToolIDs: make(map[string]struct{}),
}
defer func() {
if !s.turnActive.Load() {
turnCancel()View on GitHub (pinned to 4000b2338a)
Solutions
- Wait for the current turn to finish before sending again; queue messages at the engine level
- Check busy state before calling Send (if the session exposes one) and surface a 'busy, please wait' message to the user
- Cancel the active turn if the new message should preempt it, then resend
- Use a separate session for concurrent workloads instead of sharing one
Example fix
// before
if err := session.Send(ctx, msg, nil); err != nil { return err }
// after
if err := session.Send(ctx, msg, nil); err != nil {
if strings.Contains(err.Error(), "session is busy") {
busyQueue <- msg // enqueue until current turn completes
return nil
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
if session.IsBusy() {
return enqueueForLater(session, msg)
} Try / catch
if err := session.Send(ctx, msg, nil); err != nil {
if strings.Contains(err.Error(), "session is busy") {
return queueMessage(session, msg) // retry after turn completes
}
return err
} Prevention
- Serialize Send calls per session with a mutex or message queue
- Surface a 'busy' status to users instead of failing silently
- Debounce rapid user messages in the platform adapter before dispatching
When it happens
Trigger: Two Send() calls on the same iflow AgentSession while the first turn is still streaming (e.g. user sends a second message before the agent finishes, or a retry timer fires mid-turn).
Common situations: User sends rapid follow-up messages in the chat platform; a queued/retry path re-sends a prompt that is already running; a cron/timer job overlaps an interactive session turn.
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
- iflowSession: resolve session dir: %w
- iflowSession: start pty: %w
- %s
- iflow process failed: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/930031f1a755dba0.
Report an issue: GitHub.