{"record":{"id":"26e5cc88d140d07c","repo":"plandex-ai/plandex","slug":"error-writing-plan-apply-file-v","errorCode":null,"errorMessage":"error writing plan apply file: %v","messagePattern":"error writing plan apply file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/result_helpers.go","lineNumber":757,"sourceCode":"\tplanApply.PlanFileResultIds = resultIds\n\tplanApply.ConvoMessageDescriptionIds = descriptionIds\n\tplanApply.ConvoMessageIds = messageIds\n\n\t// Store the PlanApply object\n\tbytes, err := json.MarshalIndent(planApply, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling plan apply: %v\", err)\n\t}\n\n\tappliesDir := getPlanAppliesDir(orgId, planId)\n\terr = os.MkdirAll(appliesDir, 0755)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating applies dir: %v\", err)\n\t}\n\n\terr = os.WriteFile(filepath.Join(appliesDir, planApply.Id+\".json\"), bytes, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing plan apply file: %v\", err)\n\t}\n\n\tmsg := \"✅ Marked pending results as applied\"\n\n\tcurrentFiles := currentPlanState.CurrentPlanFiles.Files\n\tvar sortedFiles []string\n\tfor path := range currentFiles {\n\t\tsortedFiles = append(sortedFiles, path)\n\t}\n\tsort.Strings(sortedFiles)\n\tfor _, path := range sortedFiles {\n\t\tmsg += fmt.Sprintf(\"\\n • 📄 %s\", path)\n\t}\n\tmsg += \"\\n\" + \"✏️  \" + params.CommitMsg\n\n\tif loadContextRes != nil && !loadContextRes.MaxTokensExceeded {\n\t\tmsg += \"\\n\\n\" + loadContextRes.Msg\n\t}","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/result_helpers.go#L739-L775","documentation":"After creating the applies directory, ApplyPlan writes the marshalled PlanApply record with os.WriteFile at 0644. If that write fails, the OS error is wrapped with this message. It means the apply record could not be persisted even though the directory was created.","triggerScenarios":"os.WriteFile fails inside ApplyPlan — disk full, permission denied on the newly created dir, planApply.Id empty or containing path-unsafe characters, or the target .json file already exists as a directory/read-only file.","commonSituations":"Disk quota exceeded after a burst of applies; running the app under a different UID than the data dir owner; empty planApply.Id producing a bare \".json\" path; AV/backup tooling locking files on network storage.","solutions":["Check free disk space and quotas on the volume hosting the applies dir","Confirm the process has write permission on the applies directory (it was just created with 0755 — owner matters)","Verify planApply.Id is a valid non-empty UUID without path separators before writing","Read the wrapped OS error (ENOSPC/EACCES/EISDIR) and address the specific cause"],"exampleFix":"// before\nerr = os.WriteFile(filepath.Join(appliesDir, planApply.Id+\".json\"), bytes, 0644)\n// after: validate id and surface a clearer failure\nif planApply.Id == \"\" || strings.ContainsAny(planApply.Id, \"/\\\\\") {\n    return fmt.Errorf(\"invalid plan apply id: %q\", planApply.Id)\n}\nif err := os.WriteFile(filepath.Join(appliesDir, planApply.Id+\".json\"), bytes, 0644); err != nil {\n    return fmt.Errorf(\"error writing plan apply file: %v\", err)\n}","handlingStrategy":"try-catch","validationCode":"if planApply.Id == \"\" || strings.ContainsAny(planApply.Id, \"/\\\\\") {\n    return fmt.Errorf(\"invalid plan apply id: %q\", planApply.Id)\n}\nif err := unix.Access(appliesDir, unix.W_OK); err != nil {\n    return fmt.Errorf(\"applies dir not writable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"err := os.WriteFile(filepath.Join(appliesDir, planApply.Id+\".json\"), bytes, 0644)\nif err != nil {\n    var pathErr *os.PathError\n    if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.ENOSPC) {\n        return fmt.Errorf(\"disk full while writing plan apply: %v\", err)\n    }\n    return fmt.Errorf(\"error writing plan apply file: %v\", err)\n}","preventionTips":["Monitor disk usage on the data volume and alert before full","Keep file ids as generated UUIDs — never embed user input in file paths","Run cleanup/rotation of old applies to avoid quota exhaustion","Pin the process user/UID across deployments so directory ownership stays consistent"],"tags":["filesystem","go","io","disk-full"],"backgroundTag":"file-write-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}