plandex-ai/plandex · warning
plan %s branch %s already has an active stream on host %s
Error message
plan %s branch %s already has an active stream on host %s
What it means
activatePlan also consults the persisted active model stream: if db.GetActiveModelStream returns a non-nil stream, another host (or process) already owns the stream for this plan+branch. It returns this error including that stream's InternalIp so the user can find the host holding the stream.
Source
Thrown at app/server/model/plan/activate.go:46
log.Println("Waiting 100ms before checking for active plan")
time.Sleep(100 * time.Millisecond)
log.Println("Done waiting, checking for active plan")
active := GetActivePlan(plan.Id, branch)
if active != nil {
log.Printf("Tell: Active plan found for plan ID %s on branch %s\n", plan.Id, branch) // Log if an active plan is found
return nil, fmt.Errorf("plan %s branch %s already has an active stream on this host", plan.Id, branch)
}
modelStream, err := db.GetActiveModelStream(plan.Id, branch)
if err != nil {
log.Printf("Error getting active model stream: %v\n", err)
return nil, fmt.Errorf("error getting active model stream: %v", err)
}
if modelStream != nil {
log.Printf("Tell: Active model stream found for plan ID %s on branch %s on host %s\n", plan.Id, branch, modelStream.InternalIp) // Log if an active model stream is found
return nil, fmt.Errorf("plan %s branch %s already has an active stream on host %s", plan.Id, branch, modelStream.InternalIp)
}
active = CreateActivePlan(
auth.OrgId,
auth.User.Id,
plan.Id,
branch,
prompt,
buildOnly,
autoContext,
sessionId,
)
modelStream = &db.ModelStream{
OrgId: auth.OrgId,
PlanId: plan.Id,
InternalIp: host.Ip,
Branch: branch,View on GitHub (pinned to e2d772072e)
Solutions
- Go to the host identified in the error (InternalIp) and stop/cancel the existing stream, then retry.
- If the owning host is dead, manually delete the stale model stream record and retry activation.
- Add host liveness/TTL checks so dead hosts' stream rows are reaped automatically.
- Route the request to the host that already owns the stream instead of activating locally.
Example fix
// before: stale row blocks forever
// after: reap stale streams before activation
if err := db.DeleteStaleModelStreams(plan.Id, branch, staleAfter); err != nil { return err }
modelStream, err := db.GetActiveModelStream(plan.Id, branch) Defensive patterns
Strategy: validation
Validate before calling
stream, err := db.GetActiveModelStream(planId, branch)
if err == nil && stream != nil {
return fmt.Errorf("stream already active on host %s; route there or cancel it first", stream.InternalIp)
}
// safe to activate Try / catch
_, err := Tell(ctx, req)
if err != nil {
var hostErr *HostActiveError
if errors.As(err, &hostErr) {
return proxyToHost(ctx, hostErr.InternalIp, req)
}
return err
} Prevention
- Run periodic sweeps deleting stream rows of dead hosts (TTL/heartbeat)
- In multi-host setups, route requests by plan/branch ownership
- Always complete StreamDoneCh handling so rows get deleted
- Clean up orphaned stream rows after node crashes
When it happens
Trigger: Calling activatePlan when a model stream row for plan.Id + branch still exists (active on another host at modelStream.InternalIp), typically from a prior run that never completed cleanup.
Common situations: Multi-host deployments where another instance owns the branch, crashed hosts leaving orphaned stream rows, or restarts before StreamDoneCh was processed and the row deleted.
Related errors
- plan %s branch %s already has an active stream on this host
- failed to get file info for %s: %v
- failed to read file %s: %v
- failed to load context: %v
- failed to get file map: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/bf9343b193cf4829.
Report an issue: GitHub.