charmbracelet/crush · error
failed to write file: %w
Error message
failed to write file: %w
What it means
The edit tool's createNewFile path writes the new file to disk with os.WriteFile (mode 0o644) and wraps any OS-level failure in this error. It means the file content was produced but the filesystem write itself failed — this is not a permission-decision or content problem. The wrapped %w carries the underlying cause (e.g. *os.PathError).
Source
Thrown at internal/agent/tools/edit.go:165
},
)
if err != nil {
return fantasy.ToolResponse{}, err
}
if !p {
resp := NewPermissionDeniedResponse()
resp = fantasy.WithResponseMetadata(resp, EditResponseMetadata{
OldContent: "",
NewContent: content,
Additions: additions,
Removals: removals,
})
return resp, nil
}
err = os.WriteFile(filePath, []byte(content), 0o644)
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
// File can't be in the history so we create a new file history
_, err = edit.files.Create(edit.ctx, sessionID, filePath, "")
if err != nil {
// Log error but don't fail the operation
return fantasy.ToolResponse{}, fmt.Errorf("error creating file history: %w", err)
}
// Add the new content to the file history
_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, content)
if err != nil {
// Log error but don't fail the operation
slog.Error("Error creating file history version", "error", err)
}
edit.filetracker.RecordRead(edit.ctx, sessionID, filePath)
View on GitHub (pinned to 7944b8e522)
Solutions
- Check the wrapped cause in the message (%w) to identify the exact OS error (ENOENT, EACCES, ENOSPC).
- Ensure the parent directory exists (mkdir -p) and the process has write permission on it.
- Free disk space or remount the filesystem read-write if ENOSPC/EROFS is reported.
- Verify the path is not a directory and that the tool has permission (via permission allow-list) to write it.
Example fix
// before: edit tool called with new file path but parent dir missing err = os.WriteFile(filePath, []byte(content), 0o644) // after: caller ensures the directory exists first os.MkdirAll(filepath.Dir(filePath), 0o755) err = os.WriteFile(filePath, []byte(content), 0o644)
Defensive patterns
Strategy: validation
Validate before calling
func canCreateFile(path string) error {
if _, err := os.Stat(path); err == nil {
return nil // exists; edit path, not create path
}
dir := filepath.Dir(path)
fi, err := os.Stat(dir)
if err != nil {
return fmt.Errorf("parent dir missing: %w", err)
}
if !fi.IsDir() {
return errors.New("parent is not a directory")
}
if err := syscall.Access(dir, syscall.O_RDWR); err != nil {
return fmt.Errorf("dir not writable: %w", err)
}
return nil
} Try / catch
var werr *fs.PathError
if errors.As(err, &werr) {
log.Printf("write failed on %s: %v", werr.Path, werr.Err)
if errors.Is(werr.Err, syscall.ENOSPC) { freeDisk() }
} Prevention
- Check disk space before long agent sessions on small volumes.
- Keep the workspace on a read-write mount; avoid read-only containers.
- Run mkdir -p on the parent directory before programmatic edits.
- Confirm the tool's permission allow-list includes the target directory.
When it happens
Trigger: Calling the edit tool with a path for a file that does not exist (create-new branch) when the write fails: parent directory does not exist, read-only filesystem, insufficient OS permissions, disk full, or the path is actually a directory-like target.
Common situations: Running the agent in a sandbox/container with a read-only workspace, typos in the path so a parent directory is missing, editing files outside an allowed mount, or the project dir living on a full tmpfs.
Related errors
- failed to write file: %w
- %s
- failed to read file: %w
- failed to read file: %w
- error resolving working directory: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/4dfa7f43caddd58a.
Report an issue: GitHub.