{"record":{"id":"35459915f0accd28","repo":"plandex-ai/plandex","slug":"error-writing-json-file-v","errorCode":null,"errorMessage":"error writing JSON file: %v","messagePattern":"error writing JSON file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/model_settings.go","lineNumber":90,"sourceCode":"\nfunc WriteModelSettingsFile(path string, originalSettings *shared.PlanSettings) error {\n\terr := os.MkdirAll(filepath.Dir(path), 0755)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating directory: %v\", err)\n\t}\n\n\tmodelPackSchemaRoles := originalSettings.GetModelPack().ToModelPackSchema().ModelPackSchemaRoles\n\n\tclientModelPackRoles := modelPackSchemaRoles.ToClientModelPackSchemaRoles()\n\n\tbytes, err := json.MarshalIndent(clientModelPackRoles, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling model pack: %v\", err)\n\t}\n\n\terr = os.WriteFile(path, bytes, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing JSON file: %v\", err)\n\t}\n\n\terr = SaveModelPackRolesHash(path, &modelPackSchemaRoles)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error saving model pack roles hash: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc SaveModelPackRolesHash(basePath string, serverModelPack *shared.ModelPackSchemaRoles) error {\n\thashPath := basePath + \".hash\"\n\n\thash, err := serverModelPack.Hash()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error hashing model pack: %v\", err)\n\t}\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/model_settings.go#L72-L108","documentation":"After serializing, WriteModelSettingsFile writes the JSON bytes to the settings path with os.WriteFile (mode 0644). Failures are wrapped as 'error writing JSON file: %v'. The root cause is the wrapped OS error, not the JSON content.","triggerScenarios":"os.WriteFile(path, bytes, 0644) fails: the settings file is read-only, owned by another user, the directory was removed between MkdirAll and the write, the disk is full, or path points to a directory.","commonSituations":"model-settings.json opened in an editor with restrictive permissions; two CLI processes racing so the plan directory is deleted mid-write; quota-exceeded home directories on shared servers.","solutions":["Fix file/directory permissions: chmod u+w on model-settings.json and its directory","Check the wrapped OS error for ENOSPC/EDQUOT and free space or quota","Ensure no other process deleted the ~/.plandex/<planId> directory mid-operation","If a directory exists at the file path, remove it and let the CLI recreate the file"],"exampleFix":"// before\nopen /home/user/.plandex/xyz/model-settings.json: permission denied\n// after\nsudo chown -R \"$USER\" ~/.plandex && chmod -R u+rw ~/.plandex","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(path); err == nil && info.IsDir() {\n    return fmt.Errorf(\"%s is a directory; cannot write settings file\", path)\n}\nif info, err := os.Stat(path); err == nil && info.Mode().Perm()&0o200 == 0 {\n    os.Chmod(path, 0o644) // make writable before WriteModelSettingsFile\n}","typeGuard":null,"tryCatchPattern":"if err := lib.WriteModelSettingsFile(path, settings); err != nil {\n    if strings.Contains(err.Error(), \"error writing JSON file\") {\n        // check disk space/permissions on path, fix, retry\n    }\n    return err\n}","preventionTips":["Check free disk space/quota on the home filesystem","Avoid running the CLI with mixed users (sudo vs user)","Exclude ~/.plandex from sync tools that lock files","Verify the target path is not a directory"],"tags":["go","filesystem","write","permissions"],"backgroundTag":"file-write-permission-denied","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"}