charmbracelet/crush · error
error creating directory: %w
Error message
error creating directory: %w
What it means
The write tool creates missing parent directories with os.MkdirAll(dir, 0o755) before writing the file. If that fails, the tool wraps the OS error and aborts. MkdirAll fails when it lacks permission on an ancestor, an ancestor exists as a non-directory, or the filesystem rejects the create.
Source
Thrown at internal/agent/tools/write.go:91
modTime := fileInfo.ModTime().Truncate(time.Second)
lastRead := filetracker.LastReadTime(ctx, sessionID, filePath)
if modTime.After(lastRead) {
return fantasy.NewTextErrorResponse(fmt.Sprintf("File %s has been modified since it was last read.\nLast modification: %s\nLast read: %s\n\nPlease read the file again before modifying it.",
filePath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339))), nil
}
oldContent, readErr := os.ReadFile(filePath)
if readErr == nil && string(oldContent) == params.Content {
return fantasy.NewTextErrorResponse(fmt.Sprintf("File %s already contains the exact content. No changes made.", filePath)), nil
}
} else if !os.IsNotExist(err) {
return fantasy.ToolResponse{}, fmt.Errorf("error checking file: %w", err)
}
dir := filepath.Dir(filePath)
if err = os.MkdirAll(dir, 0o755); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("error creating directory: %w", err)
}
oldContent := ""
if fileInfo != nil && !fileInfo.IsDir() {
oldBytes, readErr := os.ReadFile(filePath)
if readErr == nil {
oldContent = string(oldBytes)
}
}
diff, additions, removals := diff.GenerateDiff(
oldContent,
params.Content,
strings.TrimPrefix(filePath, workingDir),
)
p, err := permissions.Request(
ctx,View on GitHub (pinned to 7944b8e522)
Solutions
- Ensure the process user can create the directory: check ownership and write permission on the nearest existing ancestor.
- Fix the path so no intermediate component is a regular file.
- Check disk space/quota (df -h, ENOSPC).
- Write within the project working directory instead of system paths.
Example fix
// before
{"file_path": "/etc/myapp/config.json", "content": "{}"}
// after
{"file_path": "config/config.json", "content": "{}"} Defensive patterns
Strategy: validation
Validate before calling
dir := filepath.Dir(targetPath)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("cannot create %s: %w", dir, err)
} Try / catch
if err != nil {
if errors.Is(err, fs.ErrPermission) {
return fmt.Errorf("mkdir denied: run the agent as a user that owns the project dir")
}
if errors.Is(err, syscall.ENOTDIR) {
return fmt.Errorf("a path component is a file, not a directory")
}
return err
} Prevention
- Use relative paths within the project root; avoid system directories.
- Ensure no file in the repo shares a name with an intended directory component.
- Monitor disk space on CI runners.
When it happens
Trigger: Target file_path has a directory component that does not exist and cannot be created — parent owned by another user/read-only mount, or an ancestor path is a regular file (ENOTDIR), or the filesystem is full (ENOSPC).
Common situations: Agent running as a non-root user writing under /etc or another root-owned path; read-only container filesystems; path like src/main.go/newdir/file.go where main.go is a file; disk quota exceeded.
Related errors
- failed to create data directory: %q %w
- failed to create parent directories: %w
- failed to create parent directories: %w
- error checking file: %w
- error writing file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/1e3097d6502482cd.
Report an issue: GitHub.