{"record":{"id":"53aaf75f39c2e381","repo":"plandex-ai/plandex","slug":"error-getting-plan-current-branch-v","errorCode":null,"errorMessage":"error getting plan current branch: %v","messagePattern":"error getting plan current branch: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/plans.go","lineNumber":180,"sourceCode":"}\n\nfunc GetCurrentBranchNamesByPlanId(planIds []string) (map[string]string, error) {\n\tif fs.HomePlandexDir == \"\" {\n\t\treturn nil, fmt.Errorf(\"HomePlandexDir not set\")\n\t}\n\n\tif CurrentProjectId == \"\" || HomeCurrentPlanPath == \"\" {\n\t\treturn nil, fmt.Errorf(\"no current project\")\n\t}\n\n\tvar mu sync.Mutex\n\tbranches := make(map[string]string)\n\terrCh := make(chan error, len(planIds))\n\tfor _, planId := range planIds {\n\t\tgo func(planId string) {\n\t\t\tbranch, err := getPlanCurrentBranch(planId)\n\t\t\tif err != nil {\n\t\t\t\terrCh <- fmt.Errorf(\"error getting plan current branch: %v\", err)\n\t\t\t} else {\n\t\t\t\tmu.Lock()\n\t\t\t\tdefer mu.Unlock()\n\t\t\t\tbranches[planId] = branch\n\t\t\t\terrCh <- nil\n\t\t\t}\n\t\t}(planId)\n\t}\n\n\tfor i := 0; i < len(planIds); i++ {\n\t\terr := <-errCh\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn branches, nil\n}","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/plans.go#L162-L198","documentation":"GetCurrentBranchNamesByPlanId fans out one goroutine per planId, each calling getPlanCurrentBranch. When any goroutine gets an error, it wraps it as 'error getting plan current branch: %v' and the collector loop returns it, aborting the whole batch lookup. It is an aggregate wrapper — the root cause is always an inner error from getPlanCurrentBranch (unset config, missing project, file read/parse failure).","triggerScenarios":"Calling GetCurrentBranchNamesByPlanId(planIds) when any plan's settings-v2.json cannot be read or parsed, or package-level globals fs.HomePlandexDir / CurrentProjectId / HomeCurrentPlanPath are empty.","commonSituations":"Running the CLI before Plandex home dir or current project was initialized; a corrupt or hand-edited settings-v2.json; permissions problems under ~/.plandex; asking for branch names of plans from another project.","solutions":["Read the wrapped '%v' suffix to identify the true inner error and fix that first","Run 'plandex init' or open a valid project so fs.HomePlandexDir, CurrentProjectId and HomeCurrentPlanPath are set","Delete or repair the malformed/unreadable settings-v2.json for the offending plan (missing file is fine — it defaults to 'main')","Check file permissions on the settings-v2.json path under HomePlandexDir"],"exampleFix":"// before\nbranches, err := GetCurrentBranchNamesByPlanId(ids)\n// after\nif fs.HomePlandexDir == \"\" || CurrentProjectId == \"\" {\n    return fmt.Errorf(\"initialize plandex project first: %w\", err)\n}\nbranches, err := GetCurrentBranchNamesByPlanId(ids)","handlingStrategy":"try-catch","validationCode":"if fs.HomePlandexDir == \"\" || CurrentProjectId == \"\" || HomeCurrentPlanPath == \"\" {\n    return fmt.Errorf(\"plandex not initialized: set home dir and open a project first\")\n}\nfor _, id := range planIds {\n    if _, err := os.Stat(filepath.Join(fs.HomePlandexDir, CurrentProjectId, id, \"settings-v2.json\")); err != nil && !os.IsNotExist(err) {\n        return fmt.Errorf(\"plan %s settings unreachable: %w\", id, err)\n    }\n}","typeGuard":"func hasProjectContext() bool {\n    return fs.HomePlandexDir != \"\" && CurrentProjectId != \"\" && HomeCurrentPlanPath != \"\"\n}","tryCatchPattern":"branches, err := GetCurrentBranchNamesByPlanId(planIds)\nif err != nil {\n    if strings.Contains(err.Error(), \"HomePlandexDir not set\") || strings.Contains(err.Error(), \"no current project\") {\n        // re-initialize / open project, then retry once\n    } else {\n        return fmt.Errorf(\"branch lookup failed: %w\", err)\n    }\n}","preventionTips":["Always initialize the Plandex home dir and open a project before calling plan APIs","Treat a missing settings-v2.json as normal (defaults to main) and only alert on read/parse failures","Log the inner wrapped error, not just the wrapper, when diagnosing batch lookups"],"tags":["go","concurrency","filesystem","configuration"],"backgroundTag":"plan-branch-lookup-failed","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"}