plandex-ai/plandex · error
failed to write %s: %s
Error message
failed to write %s: %s
What it means
After ensuring the directory exists, ApplyFiles writes the plan content with os.WriteFile(dstPath, content, 0644). A failure here (permissions, read-only FS, disk full, target is a directory) is wrapped into this error and aborts the apply.
Source
Thrown at app/cli/lib/apply.go:689
toRevert[dstPath] = types.ApplyReversion{Content: string(bytes), Mode: mode}
mu.Unlock()
}
} else {
mu.Lock()
updatedFiles = append(updatedFiles, path)
toRemoveOnRollback = append(toRemoveOnRollback, dstPath)
mu.Unlock()
// Create the directory if it doesn't exist
err := os.MkdirAll(filepath.Dir(dstPath), 0755)
if err != nil {
errCh <- fmt.Errorf("failed to create directory %s: %s", filepath.Dir(dstPath), err.Error())
return
}
}
// Write the file
err = os.WriteFile(dstPath, []byte(content), 0644)
if err != nil {
errCh <- fmt.Errorf("failed to write %s: %s", dstPath, err.Error())
return
}
errCh <- nil
}(path, content)
}
for path, remove := range toRemove {
go func(path string, remove bool) {
if !remove {
errCh <- nil
return
}
// Compute destination path
dstPath := filepath.Join(fs.ProjectRoot, path)
// Check if the file exists
var exists bool
var mode os.FileMode
info, err := os.Stat(dstPath)View on GitHub (pinned to e2d772072e)
Solutions
- Fix write permissions/ownership on the target file or its directory (chmod/chown)
- Verify dstPath is not a directory; remove the conflicting directory if the plan intends a file
- Check disk space (df -h) and remount read-only volumes as read-write
- Remove the immutable attribute (chattr -i) if set
Example fix
// before -rw-r--r-- 1 root root config.yaml # plan overwrites it as non-root // after $ sudo chown $USER config.yaml $ plandex apply
Defensive patterns
Strategy: validation
Validate before calling
// pre-check writability
if info, err := os.Stat(dstPath); err == nil {
if info.IsDir() { return fmt.Errorf("%s is a directory", dstPath) }
f, err := os.OpenFile(dstPath, os.O_WRONLY, 0)
if err != nil { return fmt.Errorf("%s not writable: %w", dstPath, err) }
f.Close()
}
if err := syscall.Access(filepath.Dir(dstPath), syscall.W_OK); err != nil {
return fmt.Errorf("directory not writable")
} Type guard
func isWritablePath(path string) bool {
return syscall.Access(path, syscall.W_OK) == nil
} Try / catch
if err := os.WriteFile(dstPath, content, 0o644); err != nil {
if errors.Is(err, fs.ErrPermission) { /* fix perms */ }
if errors.Is(err, fs.ErrExist) { /* path is a dir */ }
return fmt.Errorf("write %s: %w", dstPath, err)
} Prevention
- Check df -h for full disks before applying
- Fix ownership of files generated by root/docker as the same user as Plandex
- Never mount the project read-only when applying
- Verify target is a file, not a directory
When it happens
Trigger: os.WriteFile(dstPath, []byte(content), 0644) returns an error — write permission denied, dstPath is a directory, disk full, read-only filesystem, or immutable file attribute.
Common situations: File owned by root or another user without write permission; target path is actually a directory; container/CI filesystem mounted read-only; quota exceeded on a large generated file.
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 writing file: %v
- error writing hash file: %v
- error writing JSON file: %v
- error walking directory: %s
- failed to check if %s exists: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/d9b70ba28420fcab.
Report an issue: GitHub.