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

  1. Check the file's read permissions (chmod u+r) or fix ownership
  2. Verify the path is a regular file, not a directory
  3. Re-run the apply if a concurrent process was racing with it; ensure no other tool is mutating the same files
  4. 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

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


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/8cee06b861e2b8f5. Report an issue: GitHub.