{"record":{"id":"ca34b83dddf9ea65","repo":"plandex-ai/plandex","slug":"error-reading-settings-v2-json-v","errorCode":null,"errorMessage":"error reading settings-v2.json: %v","messagePattern":"error reading settings-v2\\.json: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/plans.go","lineNumber":220,"sourceCode":"\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\tv2Path := filepath.Join(fs.HomePlandexDir, CurrentProjectId, planId, \"settings-v2.json\")\n\n\tvar settings *types.PlanSettings\n\n\t// check if settings-v2.json exists\n\t_, err := os.Stat(v2Path)\n\tif err == nil {\n\t\t// read settings-v2.json\n\t\tvar settingsByAccount types.PlanSettingsByAccount\n\t\tbytes, err := os.ReadFile(v2Path)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error reading settings-v2.json: %v\", err)\n\t\t}\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\n\t\tsettings = settingsByAccount[auth.Current.UserId]\n\t} else if os.IsNotExist(err) {\n\t\treturn \"main\", nil\n\t} else {\n\t\treturn \"\", fmt.Errorf(\"error checking if settings-v2.json exists: %v\", err)\n\t}\n\n\tif settings == nil {\n\t\treturn \"main\", nil\n\t}\n\n\treturn settings.Branch, nil","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/plans.go#L202-L238","documentation":"When os.Stat confirms settings-v2.json exists, the function reads it with os.ReadFile. If the read fails (permissions, file deleted between stat and read, I/O error), it wraps the OS error as 'error reading settings-v2.json: %v'. Note the stat-then-read race: existence at stat time does not guarantee a successful read.","triggerScenarios":"settings-v2.json exists at HomePlandexDir/CurrentProjectId/planId/ but os.ReadFile fails — permission denied, the file vanished between Stat and ReadFile, disk I/O errors, or the path points to a directory.","commonSituations":"Running the CLI as a different user than the one who created ~/.plandex; antivirus/backup tools temporarily locking files; a broken symlink; plan directory partially deleted.","solutions":["Check and fix permissions: chmod u+r (and directory u+rx) on the settings-v2.json path","Verify the path is a regular file, not a directory or broken symlink: ls -l","Recreate the settings file (or delete it — a missing file legitimately defaults the branch to 'main')","Check disk/filesystem health if read fails with an I/O error"],"exampleFix":"// before\nbytes, err := os.ReadFile(v2Path)\nif err != nil { return \"\", fmt.Errorf(\"error reading settings-v2.json: %v\", err) }\n// after (robust)\nbytes, err := os.ReadFile(v2Path)\nif os.IsNotExist(err) { return \"main\", nil } // tolerate vanished file\nif err != nil { return \"\", fmt.Errorf(\"error reading settings-v2.json: %w\", err) }","handlingStrategy":"fallback","validationCode":"info, err := os.Stat(v2Path)\nif err == nil && !info.Mode().IsRegular() {\n    return fmt.Errorf(\"%s is not a regular file\", v2Path)\n}\nif err == nil && info.Mode().Perm()&0400 == 0 {\n    return fmt.Errorf(\"%s is not readable\", v2Path)\n}","typeGuard":null,"tryCatchPattern":"branch, err := getPlanCurrentBranch(planId)\nif err != nil && strings.Contains(err.Error(), \"error reading settings-v2.json\") {\n    // file unreadable: fall back to default branch instead of failing the batch\n    branch = \"main\"\n}","preventionTips":["Run all Plandex commands as the user who owns ~/.plandex","Avoid external tools (sync/AV) that lock files under the Plandex home dir","Prefer single-writer updates to settings-v2.json to avoid torn states"],"tags":["go","filesystem","permissions","io"],"backgroundTag":"file-read-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"}