plandex-ai/plandex · error
failed to read %s: %s
Error message
failed to read %s: %s
What it means
When the destination file exists, ApplyFiles reads its content to compare against the plan's content and record a reversion snapshot. If os.ReadFile fails (despite Stat succeeding), the goroutine emits this error and the apply aborts.
Source
Thrown at app/cli/lib/apply.go:660
var mode os.FileMode
info, err := os.Stat(dstPath)
if err == nil {
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 {
// read file content
bytes, err := os.ReadFile(dstPath)
if err != nil {
errCh <- fmt.Errorf("failed to read %s: %s", dstPath, err.Error())
return
}
// Check if the file has changed
if string(bytes) == content {
// log.Println("File is unchanged, skipping")
errCh <- nil
return
} else {
mu.Lock()
updatedFiles = append(updatedFiles, path)
toRevert[dstPath] = types.ApplyReversion{Content: string(bytes), Mode: mode}
mu.Unlock()
}
} else {
mu.Lock()
updatedFiles = append(updatedFiles, path)
toRemoveOnRollback = append(toRemoveOnRollback, dstPath)
mu.Unlock()View on GitHub (pinned to e2d772072e)
Solutions
- Check the file's read permissions (chmod u+r) or fix ownership
- Verify the path is a regular file, not a directory
- Re-run the apply if a concurrent process was racing with it; ensure no other tool is mutating the same files
- Exclude unreadable/special files from the plan
Example fix
// before $ ls -l src/config.go # -rw------- root root // after $ sudo chown $USER src/config.go $ plandex apply
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(path)
if err != nil || !info.Mode().IsRegular() {
return fmt.Errorf("%s is not a readable regular file", path)
}
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil { return fmt.Errorf("not readable: %w", err) }
f.Close() Type guard
func isReadableRegularFile(path string) bool {
info, err := os.Stat(path)
return err == nil && info.Mode().IsRegular() && info.Mode().Perm()&0o444 != 0
} Try / catch
bytes, err := os.ReadFile(dstPath)
if err != nil {
return fmt.Errorf("read %s: %w", dstPath, err)
} Prevention
- Chown project files to the user running Plandex
- Ensure plan paths point at files, not directories
- Stop concurrent watchers/tools mutating the tree during apply
- Watch for TOCTOU races between Stat and Read
When it happens
Trigger: os.ReadFile(dstPath) errors on an existing file — read permission denied, the 'file' is actually a directory, or the file was deleted/changed between Stat and Read by a concurrent process.
Common situations: Files owned by another user with no read bit; path is a directory that Stat succeeded on; concurrent builds/tools deleting files mid-apply; special files that can't be read as bytes.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- error walking directory: %s
- failed to check if %s exists: %s
- failed to write %s: %s
- failed to remove %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/8cee06b861e2b8f5.
Report an issue: GitHub.