{"record":{"id":"f197be7ba535c754","repo":"plandex-ai/plandex","slug":"error-creating-plan-dir-v","errorCode":null,"errorMessage":"error creating plan dir: %v","messagePattern":"error creating plan dir: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/plans.go","lineNumber":118,"sourceCode":"func WriteCurrentBranch(branch string) error {\n\tif fs.HomePlandexDir == \"\" {\n\t\treturn fmt.Errorf(\"HomePlandexDir not set\")\n\t}\n\n\tif CurrentProjectId == \"\" || HomeCurrentPlanPath == \"\" {\n\t\treturn fmt.Errorf(\"no current project\")\n\t}\n\n\tif CurrentPlanId == \"\" {\n\t\treturn fmt.Errorf(\"no current plan\")\n\t}\n\n\tdir := filepath.Join(fs.HomePlandexDir, CurrentProjectId, CurrentPlanId)\n\n\terr := os.MkdirAll(dir, os.ModePerm)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating plan dir: %v\", err)\n\t}\n\n\tpath := filepath.Join(dir, \"settings-v2.json\")\n\n\tvar settingsByAccount *types.PlanSettingsByAccount\n\n\tbytes, err := os.ReadFile(path)\n\tif err == nil {\n\t\terr = json.Unmarshal(bytes, &settingsByAccount)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error unmarshalling settings-v2.json: %v\", err)\n\t\t}\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"error checking if settings-v2.json exists: %v\", err)\n\t}\n\n\tif settingsByAccount == nil {\n\t\tsettingsByAccount = &types.PlanSettingsByAccount{}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/plans.go#L100-L136","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// diagnose\n$ plandex checkout main\n// error creating plan dir: mkdir ~/.plandex/p1/pl2: not a directory\n$ ls -la ~/.plandex/p1\n$ rm ~/.plandex/p1/pl2   # if it's a stray file, then retry\n$ plandex checkout main","handlingStrategy":"try-catch","validationCode":"dir := filepath.Join(fs.HomePlandexDir, lib.CurrentProjectId, lib.CurrentPlanId)\nif st, err := os.Stat(dir); err == nil && !st.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}","typeGuard":null,"tryCatchPattern":"if err := lib.WriteCurrentBranch(branch); err != nil {\n    var pe *os.PathError\n    if errors.As(err, &pe) && strings.Contains(err.Error(), \"error creating plan dir\") {\n        log.Fatalf(\"plan dir unavailable at %s: %v — check permissions/disk\", pe.Path, pe.Err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","filesystem","permissions","cli"],"backgroundTag":"mkdir-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"}