{"record":{"id":"bf9343b193cf4829","repo":"plandex-ai/plandex","slug":"plan-s-branch-s-already-has-an-active-stream-on-bf9343","errorCode":null,"errorMessage":"plan %s branch %s already has an active stream on host %s","messagePattern":"plan (.+?) branch (.+?) already has an active stream on host (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/server/model/plan/activate.go","lineNumber":46,"sourceCode":"\tlog.Println(\"Waiting 100ms before checking for active plan\")\n\ttime.Sleep(100 * time.Millisecond)\n\tlog.Println(\"Done waiting, checking for active plan\")\n\n\tactive := GetActivePlan(plan.Id, branch)\n\tif active != nil {\n\t\tlog.Printf(\"Tell: Active plan found for plan ID %s on branch %s\\n\", plan.Id, branch) // Log if an active plan is found\n\t\treturn nil, fmt.Errorf(\"plan %s branch %s already has an active stream on this host\", plan.Id, branch)\n\t}\n\n\tmodelStream, err := db.GetActiveModelStream(plan.Id, branch)\n\tif err != nil {\n\t\tlog.Printf(\"Error getting active model stream: %v\\n\", err)\n\t\treturn nil, fmt.Errorf(\"error getting active model stream: %v\", err)\n\t}\n\n\tif modelStream != nil {\n\t\tlog.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\n\t\treturn nil, fmt.Errorf(\"plan %s branch %s already has an active stream on host %s\", plan.Id, branch, modelStream.InternalIp)\n\t}\n\n\tactive = CreateActivePlan(\n\t\tauth.OrgId,\n\t\tauth.User.Id,\n\t\tplan.Id,\n\t\tbranch,\n\t\tprompt,\n\t\tbuildOnly,\n\t\tautoContext,\n\t\tsessionId,\n\t)\n\n\tmodelStream = &db.ModelStream{\n\t\tOrgId:      auth.OrgId,\n\t\tPlanId:     plan.Id,\n\t\tInternalIp: host.Ip,\n\t\tBranch:     branch,","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/activate.go#L28-L64","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: stale row blocks forever\n// after: reap stale streams before activation\nif err := db.DeleteStaleModelStreams(plan.Id, branch, staleAfter); err != nil { return err }\nmodelStream, err := db.GetActiveModelStream(plan.Id, branch)","handlingStrategy":"validation","validationCode":"stream, err := db.GetActiveModelStream(planId, branch)\nif err == nil && stream != nil {\n    return fmt.Errorf(\"stream already active on host %s; route there or cancel it first\", stream.InternalIp)\n}\n// safe to activate","typeGuard":null,"tryCatchPattern":"_, err := Tell(ctx, req)\nif err != nil {\n    var hostErr *HostActiveError\n    if errors.As(err, &hostErr) {\n        return proxyToHost(ctx, hostErr.InternalIp, req)\n    }\n    return err\n}","preventionTips":["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"],"tags":["concurrency","multi-host","stale-state","plan-stream"],"backgroundTag":"duplicate-active-stream","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}