{"record":{"id":"09c4a627786934a8","repo":"plandex-ai/plandex","slug":"planningsharedmsgs-is-empty-required-for-plannin","errorCode":null,"errorMessage":"planningSharedMsgs is empty - required for planning stage","messagePattern":"planningSharedMsgs is empty - required for planning stage","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/plan/tell_sys_prompt.go","lineNumber":49,"sourceCode":"\tcurrentStage := state.currentStage\n\n\tsysParts := []types.ExtendedChatMessagePart{}\n\n\tcreatePromptParams := prompts.CreatePromptParams{\n\t\tExecMode:          req.ExecEnabled,\n\t\tAutoContext:       req.AutoContext,\n\t\tIsUserDebug:       req.IsUserDebug,\n\t\tIsApplyDebug:      req.IsApplyDebug,\n\t\tIsGitRepo:         req.IsGitRepo,\n\t\tContextTokenLimit: contextTokenLimit,\n\t}\n\n\t// log.Println(\"getTellSysPrompt - prompt params:\", spew.Sdump(params))\n\n\tif currentStage.TellStage == shared.TellStagePlanning {\n\t\tif len(planningSharedMsgs) == 0 && !params.dryRunWithoutContext {\n\t\t\tlog.Println(\"planningSharedMsgs is empty - required for planning stage\")\n\t\t\treturn nil, fmt.Errorf(\"planningSharedMsgs is empty - required for planning stage\")\n\t\t}\n\n\t\tfor _, msg := range planningSharedMsgs {\n\t\t\tsysParts = append(sysParts, *msg)\n\t\t}\n\n\t\tif currentStage.PlanningPhase == shared.PlanningPhaseContext {\n\t\t\tlog.Println(\"Planning phase is context -- adding auto context prompt\")\n\n\t\t\tvar txt string\n\t\t\tif req.IsChatOnly {\n\t\t\t\ttxt = prompts.GetAutoContextChatPrompt(createPromptParams)\n\t\t\t} else {\n\t\t\t\ttxt = prompts.GetAutoContextTellPrompt(createPromptParams)\n\t\t\t}\n\n\t\t\tsysParts = append(sysParts, types.ExtendedChatMessagePart{\n\t\t\t\tType: openai.ChatMessagePartTypeText,","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_sys_prompt.go#L31-L67","documentation":"Thrown by getTellSysPrompt (tell_sys_prompt.go:49) when the tell stream is in the Planning stage but the planStageSharedMsgs (planningSharedMsgs) slice is empty and the call is not a dry run (params.dryRunWithoutContext is false). Planning-stage system prompts require the shared plan context messages (project context, plan context, etc.) as their base; without them the prompt would be built with no shared context, so the library refuses to construct it. Callers are execTellPlan and dryRunCalculateTokensWithoutContext.","triggerScenarios":"execTellPlan reaches the planning stage while planStageSharedMsgs was built as an empty slice — e.g. context loading produced zero messages, or a code path that composes getTellSysPromptParams forgets to populate planStageSharedMsgs during a real (non-dry-run) planning request.","commonSituations":"A regression in prompt-assembly code that skips loading plan/shared context; a plan with no loaded context files combined with a code path that doesn't fall back to a minimal shared message; custom integrations calling the tell pipeline directly without supplying planStageSharedMsgs.","solutions":["Ensure execTellPlan populates planStageSharedMsgs from the loaded plan/project context before calling getTellSysPrompt for the planning stage.","Confirm context loading (auto-load paths, plan context) returns at least one message; fix the loader if it silently returns empty.","For token-estimation paths, set dryRunWithoutContext=true so the empty-check is bypassed intentionally.","Add an earlier guard/log when planStageSharedMsgs ends up empty so the failure is caught before prompt construction."],"exampleFix":"// before\nparams := getTellSysPromptParams{planningPhaseOnlyMsgs: plannerOnly}\n// after\nif len(sharedMsgs) == 0 && !params.dryRunWithoutContext {\n    return nil, fmt.Errorf(\"cannot start planning stage: no shared plan context loaded\")\n}\nparams := getTellSysPromptParams{planStageSharedMsgs: sharedMsgs, planningPhaseOnlyMsgs: plannerOnly}","handlingStrategy":"validation","validationCode":"func canBuildPlanningPrompt(sharedMsgs []*types.ExtendedChatMessagePart, dryRun bool) error {\n    if len(sharedMsgs) == 0 && !dryRun {\n        return fmt.Errorf(\"planning stage requires planStageSharedMsgs; got %d messages\", len(sharedMsgs))\n    }\n    return nil\n}","typeGuard":"func hasPlanningSharedMsgs(p getTellSysPromptParams) bool {\n    return p.dryRunWithoutContext || len(p.planStageSharedMsgs) > 0\n}","tryCatchPattern":"sysParts, err := state.getTellSysPrompt(params)\nif err != nil {\n    if strings.Contains(err.Error(), \"planningSharedMsgs is empty\") {\n        // rebuild shared context then retry once\n        if sharedMsgs, lerr := loadPlanStageSharedMsgs(state); lerr == nil {\n            params.planStageSharedMsgs = sharedMsgs\n            sysParts, err = state.getTellSysPrompt(params)\n        }\n    }\n    if err != nil { return err }\n}","preventionTips":["Always populate planStageSharedMsgs before entering the planning stage.","Log when context loading returns zero messages instead of proceeding silently.","Use dryRunWithoutContext=true only for token estimation, never real streams.","Unit-test prompt assembly for the planning stage with an empty-context plan."],"tags":["prompt","planning-stage","missing-context","internal-state"],"backgroundTag":"missing-required-context","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}