charmbracelet/crush · error

error writing file: %w

Error message

error writing file: %w

What it means

The final os.WriteFile(filePath, content, 0o644) failed, so the target file was not written. This is the core write step of the tool; any OS-level write error (permissions, no space, target is a directory, file locked by immutable attribute) surfaces here wrapped.

Source

Thrown at internal/agent/tools/write.go:139

					},
				},
			)
			if err != nil {
				return fantasy.ToolResponse{}, err
			}
			if !p {
				resp := NewPermissionDeniedResponse()
				resp = fantasy.WithResponseMetadata(resp, WriteResponseMetadata{
					Diff:      diff,
					Additions: additions,
					Removals:  removals,
				})
				return resp, nil
			}

			err = os.WriteFile(filePath, []byte(params.Content), 0o644)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("error writing file: %w", err)
			}

			// Check if file exists in history
			file, err := files.GetByPathAndSession(ctx, filePath, sessionID)
			if err != nil {
				_, err = files.Create(ctx, sessionID, filePath, oldContent)
				if err != nil {
					// Log error but don't fail the operation
					return fantasy.ToolResponse{}, fmt.Errorf("error creating file history: %w", err)
				}
			}
			if file.Content != oldContent {
				// User manually changed the content; store an intermediate version
				_, err = files.CreateVersion(ctx, sessionID, filePath, oldContent)
				if err != nil {
					slog.Error("Error creating file history version", "error", err)
				}
			}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the target is not a directory and is writable by the process user (ls -la).
  2. Fix permissions/ownership (chmod/chown) or run the agent as a user with access.
  3. Free disk space if ENOSPC.
  4. Remove immutable attributes if set (chattr -i).

Example fix

// before
{"file_path": "build/output", "content": "..."}  // build/output is a directory

// after
{"file_path": "build/output/result.txt", "content": "..."}
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(targetPath); err == nil && info.IsDir() {
    return fmt.Errorf("%s is a directory, not a file", targetPath)
}
if info, err := os.Stat(targetPath); err == nil {
    f, oerr := os.OpenFile(targetPath, os.O_WRONLY, 0)
    if oerr != nil {
        return fmt.Errorf("%s is not writable by this user", targetPath)
    }
    f.Close()
}

Try / catch

if errors.Is(err, fs.ErrPermission) { /* fix chmod/chown */ }
if errors.Is(err, syscall.ENOSPC) { /* free disk space */ }
if errors.Is(err, syscall.EISDIR) { /* target is a directory */ }

Prevention

When it happens

Trigger: filePath exists as a directory (IsDir case slipped through), the file is read-only or owned by another user (EACCES), disk is full (ENOSPC), or an immutable flag (chattr +i) is set.

Common situations: Agent tries to overwrite a protected file (e.g. ~/.ssh, system configs) without permission; writing to a path that is actually a directory; ENOSPC on CI runners with small disks; root-owned files in repos checked out with restrictive modes.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/4d4fc370ceaf0090. Report an issue: GitHub.