charmbracelet/crush · error
failed to write file: %w
Error message
failed to write file: %w
What it means
This error is returned when os.WriteFile fails to persist the new content to params.FilePath after the symbol replacement was computed and permission was granted. Common wrapped causes are read-only filesystem, permission denied, disk full, or the parent directory no longer existing.
Source
Thrown at internal/agent/tools/lsp_replace_symbol.go:161
NewContent: newContent,
},
})
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("permission request failed: %w", err)
}
if !granted {
return NewPermissionDeniedResponse(), nil
}
}
if files != nil && sessionID != "" {
if _, err := files.CreateVersion(ctx, sessionID, params.FilePath, string(content)); err != nil {
slog.Warn("Failed to create file version before replace", "path", params.FilePath, "error", err)
}
}
if err := os.WriteFile(params.FilePath, []byte(newContent), 0o644); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
if filetracker != nil && sessionID != "" {
filetracker.RecordRead(ctx, sessionID, params.FilePath)
}
notifyLSPs(ctx, lspManager, params.FilePath)
var summary string
switch action {
case "replace":
summary = fmt.Sprintf("Replaced symbol '%s' in %s (lines %d-%d)", params.Symbol, params.FilePath, startLine+1, endLine+1)
case "add_before":
summary = fmt.Sprintf("Inserted before symbol '%s' in %s (before line %d)", params.Symbol, params.FilePath, startLine+1)
case "add_after":
summary = fmt.Sprintf("Inserted after symbol '%s' in %s (after line %d)", params.Symbol, params.FilePath, endLine+1)
case "delete":
summary = fmt.Sprintf("Deleted symbol '%s' from %s (lines %d-%d)", params.Symbol, params.FilePath, startLine+1, endLine+1)View on GitHub (pinned to 7944b8e522)
Solutions
- Check the wrapped OS error (EACCES, ENOSPC, EROFS) and address the specific cause.
- Verify the file and directory are writable: ls -l and touch the file as the same user.
- Free disk space or raise quota if ENOSPC.
- Restore the file if it was deleted between read and write, then re-run the tool.
Example fix
// before
if err := os.WriteFile(params.FilePath, []byte(newContent), 0o644); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
// after
if err := os.WriteFile(params.FilePath, []byte(newContent), 0o644); err != nil {
slog.Error("Failed to write file after symbol replace", "path", params.FilePath, "error", err)
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if err := unix.Access(filePath, unix.W_OK); err != nil {
return fmt.Errorf("file not writable: %s: %w", filePath, err)
} Try / catch
if err := os.WriteFile(path, data, 0o644); err != nil {
switch {
case errors.Is(err, fs.ErrPermission):
// fix permissions or choose another path
case errors.Is(err, syscall.ENOSPC):
// free disk space
}
return err
} Prevention
- Verify write permission on files before requesting symbol replacement.
- Keep target directories writable and monitor disk space.
- Avoid running in read-only container filesystems for editing workflows.
- Close editors/processes that lock or chmod files mid-session.
When it happens
Trigger: os.WriteFile returns an error during lsp_replace_symbol: file made read-only between read and write, disk quota/full, filesystem mounted read-only (container), or the file was removed by another process.
Common situations: Editor or another process locked/changed permissions on the file; running in a read-only container FS; ENOSPC on a full disk; saving to a path outside a writable mount.
Related errors
- failed to write file: %w
- failed to read file: %w
- error resolving working directory: %w
- error resolving file path: %w
- error checking file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/65dd93ec6707e204.
Report an issue: GitHub.