plandex-ai/plandex · error
error creating plan dir: %v
Error message
error creating plan dir: %v
What it means
After validating globals, WriteCurrentBranch ensures the plan directory ~/.plandex/<projectId>/<planId> exists with os.MkdirAll(dir, os.ModePerm). If that filesystem call fails — permissions, disk full, path is a file, etc. — the error is wrapped as 'error creating plan dir: %v'. The inner OS error is preserved in the message.
Source
Thrown at app/cli/lib/plans.go:118
func WriteCurrentBranch(branch string) error {
if fs.HomePlandexDir == "" {
return fmt.Errorf("HomePlandexDir not set")
}
if CurrentProjectId == "" || HomeCurrentPlanPath == "" {
return fmt.Errorf("no current project")
}
if CurrentPlanId == "" {
return fmt.Errorf("no current plan")
}
dir := filepath.Join(fs.HomePlandexDir, CurrentProjectId, CurrentPlanId)
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return fmt.Errorf("error creating plan dir: %v", err)
}
path := filepath.Join(dir, "settings-v2.json")
var settingsByAccount *types.PlanSettingsByAccount
bytes, err := os.ReadFile(path)
if err == nil {
err = json.Unmarshal(bytes, &settingsByAccount)
if err != nil {
return fmt.Errorf("error unmarshalling settings-v2.json: %v", err)
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking if settings-v2.json exists: %v", err)
}
if settingsByAccount == nil {
settingsByAccount = &types.PlanSettingsByAccount{}View on GitHub (pinned to e2d772072e)
Solutions
- Check the wrapped OS error in the message: fix the specific cause (permissions with chmod/chown, delete the blocking file, free disk space).
- Verify ~/.plandex is a writable directory owned by the current user; avoid running the CLI with sudo.
- If ids look wrong, repair project/plan state (current-plans-v2.json) so CurrentProjectId/CurrentPlanId are valid id strings.
Example fix
// diagnose $ plandex checkout main // error creating plan dir: mkdir ~/.plandex/p1/pl2: not a directory $ ls -la ~/.plandex/p1 $ rm ~/.plandex/p1/pl2 # if it's a stray file, then retry $ plandex checkout main
Defensive patterns
Strategy: try-catch
Validate before calling
dir := filepath.Join(fs.HomePlandexDir, lib.CurrentProjectId, lib.CurrentPlanId)
if st, err := os.Stat(dir); err == nil && !st.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
} Try / catch
if err := lib.WriteCurrentBranch(branch); err != nil {
var pe *os.PathError
if errors.As(err, &pe) && strings.Contains(err.Error(), "error creating plan dir") {
log.Fatalf("plan dir unavailable at %s: %v — check permissions/disk", pe.Path, pe.Err)
}
return err
} Prevention
- Never run the CLI under sudo; ~/.plandex should be owned by your user.
- Monitor disk space; MkdirAll fails on full disks.
- Inspect ~/.plandex periodically for stray files that shadow plan directories.
When it happens
Trigger: os.MkdirAll fails for ~/.plandex/<projectId>/<planId>: parent path exists as a regular file, read-only filesystem, permission denied, disk full, or an invalid path component (e.g. CurrentProjectId containing path separators or reserved names).
Common situations: A stray file named like a plan id blocking directory creation; ~/.plandex owned by another user after running with sudo; read-only home dir or full disk; corrupted project/plan ids containing '/' breaking the joined path.
Related errors
- error checking if settings-v2.json exists: %v
- no project root found
- error walking directory: %s
- failed to check if %s exists: %s
- failed to read %s: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/f197be7ba535c754.
Report an issue: GitHub.