plandex-ai/plandex · error

failed to write %s: %w

Error message

failed to write %s: %w

What it means

This error wraps the failure of os.WriteFile while a rewind/restore operation materializes files from stored content in a goroutine. It means the directory was created successfully but writing the file bytes to dstPath failed. The underlying os error (permissions, disk full, path issues) is included via %w.

Source

Thrown at app/cli/lib/rewind.go:297

				}
				// Mark parent directory for cleanup
				parentDir := filepath.Dir(dstPath)
				mu.Lock()
				dirsToCheck[parentDir] = true
				mu.Unlock()
				errCh <- nil
				return
			}

			// Ensure directory exists
			if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil {
				errCh <- fmt.Errorf("failed to create directory for %s: %w", path, err)
				return
			}

			// Write the file
			if err := os.WriteFile(dstPath, []byte(content), 0644); err != nil {
				errCh <- fmt.Errorf("failed to write %s: %w", path, err)
				return
			}

			errCh <- nil
		}(path, content)
	}

	// Collect any errors
	for i := 0; i < len(requiredChanges); i++ {
		if err := <-errCh; err != nil {
			return err
		}
	}

	// Clean up empty directories
	for dir := range dirsToCheck {
		if err := RemoveEmptyDirs(dir, fs.ProjectRoot); err != nil {
			// Log but don't fail the operation for directory cleanup errors

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check disk space (df -h) and free space if full
  2. Verify write permissions on the destination directory and file (chmod/chown)
  3. Check whether dstPath exists as a directory and remove/rename it
  4. Re-run the rewind from a writable checkout

Example fix

// before
if err := os.WriteFile(dstPath, []byte(content), 0644); err != nil { ... }
// after
if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil { ... }
if info, err := os.Stat(dstPath); err == nil && info.IsDir() { os.RemoveAll(dstPath) }
if err := os.WriteFile(dstPath, []byte(content), 0644); err != nil { ... }
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling rewind/restore
if st, err := os.Stat(projectDir); err != nil || !st.IsDir() {
    return fmt.Errorf("project dir not writable: %v", err)
}
if unix.Access(projectDir, unix.W_OK) != nil {
    return fmt.Errorf("no write permission on %s", projectDir)
}

Type guard

func isWritableDir(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.IsDir() && unix.Access(path, unix.W_OK) == nil
}

Try / catch

err := <-errCh
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && perr.Err == syscall.ENOSPC {
        // handle disk-full: free space and retry
    }
    return err
}

Prevention

When it happens

Trigger: os.WriteFile(dstPath, content, 0644) fails during a rewind restore: read-only filesystem, insufficient permissions, disk quota exceeded, dstPath is actually a directory, or path exceeds filesystem limits.

Common situations: Restoring a checkpoint into a directory where a subpath exists as a directory with the target file's name; project on a mounted read-only volume; out of disk space; file locked/owned by another user after switching environments.

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


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