plandex-ai/plandex · error
active plan not found for plan %s and branch %s
Error message
active plan not found for plan %s and branch %s
What it means
genPlanDescription needs the active plan (for its context, session ID, and cancellation scope) before generating a plan/commit description via the LLM. When GetActivePlan returns nil for the plan ID + branch, it notifies and returns a 500 ApiError. The description cannot be generated without the live plan session.
Source
Thrown at app/server/model/plan/commit_msg.go:34
shared "plandex-shared"
"github.com/sashabaranov/go-openai"
)
func (state *activeTellStreamState) genPlanDescription() (*db.ConvoMessageDescription, *shared.ApiError) {
auth := state.auth
plan := state.plan
planId := plan.Id
branch := state.branch
settings := state.settings
clients := state.clients
authVars := state.authVars
orgUserConfig := state.orgUserConfig
config := settings.GetModelPack().CommitMsg
activePlan := GetActivePlan(planId, branch)
if activePlan == nil {
go notify.NotifyErr(notify.SeverityError, fmt.Errorf("active plan not found for plan %s and branch %s", planId, branch))
return nil, &shared.ApiError{
Type: shared.ApiErrorTypeOther,
Status: http.StatusInternalServerError,
Msg: fmt.Sprintf("active plan not found for plan %s and branch %s", planId, branch),
}
}
baseModelConfig := config.GetBaseModelConfig(authVars, settings, orgUserConfig)
var sysPrompt string
var tools []openai.Tool
var toolChoice *openai.ToolChoice
if baseModelConfig.PreferredOutputFormat == shared.ModelOutputFormatXml {
sysPrompt = prompts.SysDescribeXml
} else {
sysPrompt = prompts.SysDescribeView on GitHub (pinned to e2d772072e)
Solutions
- Verify the planId and branch match the currently streaming plan (GET the plan's status first)
- Retry the tell request so the plan is re-activated before description generation
- Check server logs for an earlier Stop or DeleteActivePlan call for this plan
- Report/persist a description fallback so a finished plan doesn't lose its commit message
Example fix
// before
desc, apiErr := state.genPlanDescription()
// after: check the plan is still active first
if modelPlan.GetActivePlan(planId, branch) == nil {
log.Println("plan no longer active; skipping description")
return
}
desc, apiErr := state.genPlanDescription() Defensive patterns
Strategy: try-catch
Validate before calling
// ensure plan is streaming before asking for a description resp, _ := http.Get(baseURL + "/plans/" + planId + "/" + branch + "/status") // only proceed if status indicates an active/streaming plan
Try / catch
desc, apiErr := state.genPlanDescription()
if apiErr != nil && strings.Contains(apiErr.Msg, "active plan not found") {
log.Printf("plan %s/%s deactivated before description; skipping", planId, branch)
return
} Prevention
- Don't stop or disconnect the plan mid-stream; descriptions are generated at stream end
- Keep the plan active until the description step completes
- Verify branch spelling in all API calls
- Handle finished plans gracefully — description is not required for correctness
When it happens
Trigger: The tell stream that should have registered the active plan has ended (finished, errored, stopped, or deleted via DeleteActivePlan) before genPlanDescription runs; or the planId/branch pair passed to the stream does not match any registered active plan.
Common situations: Plan finished extremely fast and was deactivated before the description step; concurrent Stop request during streaming; using a stale planId after a server restart; branch name typo in the API call.
Related errors
- error getting plan applies: %v
- error getting current plan files: %v
- error getting current plan state: %v
- no active plan with id %s
- Error rejecting result:
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/1bd9422d952206cb.
Report an issue: GitHub.