{"record":{"id":"62d866368ce25054","repo":"plandex-ai/plandex","slug":"error-creating-convo-message-descriptions-dir-v","errorCode":null,"errorMessage":"error creating convo message descriptions dir: %v","messagePattern":"error creating convo message descriptions dir: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/plan_helpers.go","lineNumber":315,"sourceCode":"}\n\nfunc IncNumNonDraftPlans(userId string, tx *sqlx.Tx) error {\n\t_, err := tx.Exec(\"UPDATE users SET num_non_draft_plans = num_non_draft_plans + 1 WHERE id = $1\", userId)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error updating user num_non_draft_plans: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc StoreDescription(description *ConvoMessageDescription) error {\n\tdescriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)\n\n\terr := os.MkdirAll(descriptionsDir, os.ModePerm)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating convo message descriptions dir: %v\", err)\n\t}\n\n\tfor _, op := range description.Operations {\n\t\tif op.Content != \"\" {\n\t\t\tquoted := strconv.Quote(op.Content)\n\t\t\top.Content = quoted[1 : len(quoted)-1]\n\t\t}\n\t\tif op.Description != \"\" {\n\t\t\tquoted := strconv.Quote(op.Description)\n\t\t\top.Description = quoted[1 : len(quoted)-1]\n\t\t}\n\t}\n\n\tnow := time.Now()\n\n\tif description.Id == \"\" {\n\t\tdescription.Id = uuid.New().String()\n\t\tdescription.CreatedAt = now","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/plan_helpers.go#L297-L333","documentation":"StoreDescription persists a convo message description as a JSON file under a per-plan directory. Before writing files it calls os.MkdirAll to create the descriptions directory; if the OS refuses (permissions, path issues, not a directory), the failure is wrapped with this message.","triggerScenarios":"os.MkdirAll(descriptionsDir, os.ModePerm) returns an error: parent path component is a regular file, permission denied on the storage volume, disk-full can surface here in some filesystems, or an invalid path built from OrgId/PlanId.","commonSituations":"Deployments where the app runs as a non-root user without write access to the data directory; volume mounted read-only; a file accidentally created at the same path as the expected directory; container missing the persistent volume mount.","solutions":["Check OS permissions on the parent directory of the descriptions dir","Confirm no regular file exists at any path component of descriptionsDir","Verify the storage volume is mounted read-write in the deployment","Ensure OrgId/PlanId values do not introduce illegal path characters","Pre-create the base data directory with correct ownership at deploy time"],"exampleFix":"// before\ndescriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)\nerr := os.MkdirAll(descriptionsDir, os.ModePerm)\nif err != nil {\n    return fmt.Errorf(\"error creating convo message descriptions dir: %v\", err)\n}\n// after\ndescriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)\nif err := os.MkdirAll(descriptionsDir, 0o755); err != nil {\n    return fmt.Errorf(\"error creating convo message descriptions dir %s: %w\", descriptionsDir, err)\n}","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(filepath.Dir(descriptionsDir)); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", filepath.Dir(descriptionsDir))\n}","typeGuard":null,"tryCatchPattern":"if err := StoreDescription(desc); err != nil {\n    if errors.Is(err, os.ErrPermission) {\n        // alert: storage volume permissions wrong\n    }\n    return err\n}","preventionTips":["Pre-create and chown the base data directory at deploy time","Mount storage volumes read-write and verify in startup checks","Sanitize OrgId/PlanId before using them in paths","Run the app as a user with write access to the data dir"],"tags":["filesystem","io","permissions","go"],"backgroundTag":"mkdir-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"}