plandex-ai/plandex · error
error writing plan apply file: %v
Error message
error writing plan apply file: %v
What it means
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.
Source
Thrown at app/server/db/result_helpers.go:757
planApply.PlanFileResultIds = resultIds
planApply.ConvoMessageDescriptionIds = descriptionIds
planApply.ConvoMessageIds = messageIds
// Store the PlanApply object
bytes, err := json.MarshalIndent(planApply, "", " ")
if err != nil {
return fmt.Errorf("error marshalling plan apply: %v", err)
}
appliesDir := getPlanAppliesDir(orgId, planId)
err = os.MkdirAll(appliesDir, 0755)
if err != nil {
return fmt.Errorf("error creating applies dir: %v", err)
}
err = os.WriteFile(filepath.Join(appliesDir, planApply.Id+".json"), bytes, 0644)
if err != nil {
return fmt.Errorf("error writing plan apply file: %v", err)
}
msg := "✅ Marked pending results as applied"
currentFiles := currentPlanState.CurrentPlanFiles.Files
var sortedFiles []string
for path := range currentFiles {
sortedFiles = append(sortedFiles, path)
}
sort.Strings(sortedFiles)
for _, path := range sortedFiles {
msg += fmt.Sprintf("\n • 📄 %s", path)
}
msg += "\n" + "✏️ " + params.CommitMsg
if loadContextRes != nil && !loadContextRes.MaxTokensExceeded {
msg += "\n\n" + loadContextRes.Msg
}View on GitHub (pinned to e2d772072e)
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
Example fix
// before
err = os.WriteFile(filepath.Join(appliesDir, planApply.Id+".json"), bytes, 0644)
// after: validate id and surface a clearer failure
if planApply.Id == "" || strings.ContainsAny(planApply.Id, "/\\") {
return fmt.Errorf("invalid plan apply id: %q", planApply.Id)
}
if err := os.WriteFile(filepath.Join(appliesDir, planApply.Id+".json"), bytes, 0644); err != nil {
return fmt.Errorf("error writing plan apply file: %v", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if planApply.Id == "" || strings.ContainsAny(planApply.Id, "/\\") {
return fmt.Errorf("invalid plan apply id: %q", planApply.Id)
}
if err := unix.Access(appliesDir, unix.W_OK); err != nil {
return fmt.Errorf("applies dir not writable: %v", err)
} Try / catch
err := os.WriteFile(filepath.Join(appliesDir, planApply.Id+".json"), bytes, 0644)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.ENOSPC) {
return fmt.Errorf("disk full while writing plan apply: %v", err)
}
return fmt.Errorf("error writing plan apply file: %v", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- error reading settings-v2.json: %v
- failed to save the downloaded archive: %w
- failed to seek in temporary file: %w
- error reading convo dir: %v
- error reading convo file: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/26e5cc88d140d07c.
Report an issue: GitHub.