plandex-ai/plandex · error
failed to remove %s: %s
Error message
failed to remove %s: %s
What it means
After snapshotting content for rollback, ApplyFiles deletes the file with os.Remove. If removal fails for any reason other than the file already not existing, this error is emitted and the apply aborts.
Source
Thrown at app/cli/lib/apply.go:727
exists = true
mode = info.Mode()
} else {
if os.IsNotExist(err) {
exists = false
} else {
errCh <- fmt.Errorf("failed to check if %s exists: %s", dstPath, err.Error())
return
}
}
if exists {
content, err := os.ReadFile(dstPath)
if err != nil {
errCh <- fmt.Errorf("failed to read %s: %s", dstPath, err.Error())
return
}
err = os.Remove(dstPath)
if err != nil && !os.IsNotExist(err) {
errCh <- fmt.Errorf("failed to remove %s: %s", dstPath, err.Error())
return
}
mu.Lock()
toRevert[dstPath] = types.ApplyReversion{Content: string(content), Mode: mode}
mu.Unlock()
}
errCh <- nil
}(path, remove)
}
for i := 0; i < totalOps; i++ {
err := <-errCh
if err != nil {
return nil, nil, err
}
}
return updatedFiles, &types.ApplyRollbackPlan{View on GitHub (pinned to e2d772072e)
Solutions
- Ensure the containing directory is writable (chmod/chown the directory)
- If the target is a directory, remove it with rm -rf manually or fix the plan (os.Remove doesn't recurse)
- Remove immutable attributes (chattr -i) if set
- Re-run apply on a read-write filesystem from the correct project root
Example fix
// before drwxr-xr-x 2 user user . # cwd not writable -> cannot unlink files // after $ chmod u+w . # or chown the directory $ plandex apply
Defensive patterns
Strategy: validation
Validate before calling
// removal requires write permission on the PARENT directory
parent := filepath.Dir(dstPath)
if err := syscall.Access(parent, syscall.W_OK); err != nil {
return fmt.Errorf("%s not writable; cannot unlink files in it", parent)
}
if info, err := os.Stat(dstPath); err == nil && info.IsDir() {
return fmt.Errorf("%s is a directory; os.Remove cannot recurse", dstPath)
} Type guard
func canUnlink(path string) bool {
return syscall.Access(filepath.Dir(path), syscall.W_OK) == nil
} Try / catch
if err := os.Remove(dstPath); err != nil && !os.IsNotExist(err) {
if errors.Is(err, fs.ErrPermission) { /* make parent writable */ }
return fmt.Errorf("remove %s: %w", dstPath, err)
} Prevention
- Remember: unlinking needs write permission on the directory, not the file
- Use rm -rf (or recursive removal) for directories, not file-removal plans
- Clear immutable flags on files that must be deleted
- Ensure the project filesystem is writable before applying
When it happens
Trigger: os.Remove(dstPath) fails and the error is not os.IsNotExist — write permission missing on the containing directory, file is a non-empty directory, file is immutable, or the filesystem is read-only.
Common situations: Directory not writable by the current user (removal requires directory write permission, not file permission); plan tries to remove a directory path; immutable/locked files on mounted volumes.
Related errors
- error walking directory: %s
- failed to check if %s exists: %s
- failed to read %s: %s
- failed to write %s: %s
- failed to read the file %s: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/3240ec97bc6386e4.
Report an issue: GitHub.