plandex-ai/plandex · error
planningSharedMsgs is empty - required for planning stage
Error message
planningSharedMsgs is empty - required for planning stage
What it means
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.
Source
Thrown at app/server/model/plan/tell_sys_prompt.go:49
currentStage := state.currentStage
sysParts := []types.ExtendedChatMessagePart{}
createPromptParams := prompts.CreatePromptParams{
ExecMode: req.ExecEnabled,
AutoContext: req.AutoContext,
IsUserDebug: req.IsUserDebug,
IsApplyDebug: req.IsApplyDebug,
IsGitRepo: req.IsGitRepo,
ContextTokenLimit: contextTokenLimit,
}
// log.Println("getTellSysPrompt - prompt params:", spew.Sdump(params))
if currentStage.TellStage == shared.TellStagePlanning {
if len(planningSharedMsgs) == 0 && !params.dryRunWithoutContext {
log.Println("planningSharedMsgs is empty - required for planning stage")
return nil, fmt.Errorf("planningSharedMsgs is empty - required for planning stage")
}
for _, msg := range planningSharedMsgs {
sysParts = append(sysParts, *msg)
}
if currentStage.PlanningPhase == shared.PlanningPhaseContext {
log.Println("Planning phase is context -- adding auto context prompt")
var txt string
if req.IsChatOnly {
txt = prompts.GetAutoContextChatPrompt(createPromptParams)
} else {
txt = prompts.GetAutoContextTellPrompt(createPromptParams)
}
sysParts = append(sysParts, types.ExtendedChatMessagePart{
Type: openai.ChatMessagePartTypeText,View on GitHub (pinned to e2d772072e)
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.
Example fix
// before
params := getTellSysPromptParams{planningPhaseOnlyMsgs: plannerOnly}
// after
if len(sharedMsgs) == 0 && !params.dryRunWithoutContext {
return nil, fmt.Errorf("cannot start planning stage: no shared plan context loaded")
}
params := getTellSysPromptParams{planStageSharedMsgs: sharedMsgs, planningPhaseOnlyMsgs: plannerOnly} Defensive patterns
Strategy: validation
Validate before calling
func canBuildPlanningPrompt(sharedMsgs []*types.ExtendedChatMessagePart, dryRun bool) error {
if len(sharedMsgs) == 0 && !dryRun {
return fmt.Errorf("planning stage requires planStageSharedMsgs; got %d messages", len(sharedMsgs))
}
return nil
} Type guard
func hasPlanningSharedMsgs(p getTellSysPromptParams) bool {
return p.dryRunWithoutContext || len(p.planStageSharedMsgs) > 0
} Try / catch
sysParts, err := state.getTellSysPrompt(params)
if err != nil {
if strings.Contains(err.Error(), "planningSharedMsgs is empty") {
// rebuild shared context then retry once
if sharedMsgs, lerr := loadPlanStageSharedMsgs(state); lerr == nil {
params.planStageSharedMsgs = sharedMsgs
sysParts, err = state.getTellSysPrompt(params)
}
}
if err != nil { return err }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- implementationMsgs not supported during planning phase
- implementationMsgs is nil - required for implementation stag
- Prompt message isn't set
- error prompting auto add domain users: %v
- failed to get map file info for %s - should already be set
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/09c4a627786934a8.
Report an issue: GitHub.