charmbracelet/crush · error
failed to write file: %w
Error message
failed to write file: %w
What it means
os.WriteFile failed while persisting the newly created (or edited) file to disk after the edits were applied in memory. The error is wrapped verbatim from the OS, so the cause (permissions, disk full, is-a-directory) is in the %w suffix. All applied edits are discarded at this point because the write failed.
Source
Thrown at internal/agent/tools/multiedit.go:218
return fantasy.ToolResponse{}, err
}
if !p {
resp := NewPermissionDeniedResponse()
resp = fantasy.WithResponseMetadata(resp, MultiEditResponseMetadata{
OldContent: "",
NewContent: currentContent,
Additions: additions,
Removals: removals,
EditsApplied: editsApplied,
EditsFailed: failedEdits,
})
return resp, nil
}
// Write the file
err = os.WriteFile(params.FilePath, []byte(currentContent), 0o644)
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
// Update file history
_, err = edit.files.Create(edit.ctx, sessionID, params.FilePath, "")
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("error creating file history: %w", err)
}
_, err = edit.files.CreateVersion(edit.ctx, sessionID, params.FilePath, currentContent)
if err != nil {
slog.Error("Error creating file history version", "error", err)
}
edit.filetracker.RecordRead(edit.ctx, sessionID, params.FilePath)
var message string
if len(failedEdits) > 0 {
message = fmt.Sprintf("File created with %d of %d edits: %s (%d edit(s) failed)", editsApplied, len(params.Edits), params.FilePath, len(failedEdits))View on GitHub (pinned to 7944b8e522)
Solutions
- Read the wrapped OS error in the message and address it (chmod/chown the file or directory)
- Check that file_path is not an existing directory
- Free disk space if ENOSPC
- Re-run the edit once the filesystem condition is resolved
Example fix
// before # ls -l src src/new.go: directory (target of write) // after # remove/rename the blocking directory or choose a different file path, then retry the MultiEdit call
Defensive patterns
Strategy: try-catch
Validate before calling
if st, err := os.Stat(path); err == nil && st.IsDir() {
return fmt.Errorf("%s is a directory", path)
}
if err := unix.Access(filepath.Dir(path), unix.W_OK); err != nil {
return fmt.Errorf("no write permission in %s", filepath.Dir(path))
} Try / catch
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr, syscall.ENOSPC) {
// free disk space and retry
} Prevention
- Confirm target isn't an existing directory before editing
- Watch disk usage in CI/container environments
- Run the agent as a user with write access to the repo
- Handle EACCES/ENOSPC distinctly when wrapping
When it happens
Trigger: os.WriteFile(params.FilePath, content, 0o644) returns an error: target path is an existing directory (EISDIR), no write permission (EACCES), disk full (ENOSPC), or the path was deleted/replaced concurrently.
Common situations: Agent tries to write over a directory path; container user lacks write access to the repo; quota/ENOSPC on the volume; file locked by another process on some filesystems.
Related errors
- failed to create parent directories: %w
- failed to create parent directories: %w
- failed to create output file: %w
- failed to access file: %w
- failed to create parent directories: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/84bd51112edda251.
Report an issue: GitHub.