charmbracelet/crush · error
failed to create parent directories: %w
Error message
failed to create parent directories: %w
What it means
os.MkdirAll failed while creating the parent directories of the destination file path before writing the download. The wrapped error contains the OS-level reason (permission denied, path exists as a file, read-only filesystem, etc.).
Source
Thrown at internal/agent/tools/download.go:139
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("User-Agent", "crush/1.0")
resp, err := client.Do(req)
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to download from URL: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fantasy.NewTextErrorResponse(fmt.Sprintf("Request failed with status code: %d", resp.StatusCode)), nil
}
// Create parent directories if they don't exist
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to create parent directories: %w", err)
}
// Create the output file
outFile, err := os.Create(filePath)
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to create output file: %w", err)
}
defer outFile.Close()
// Copy data without an explicit size limit.
// The overall download is still constrained by the HTTP client's timeout
// and any upstream server limits.
bytesWritten, err := io.Copy(outFile, resp.Body)
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
contentType := resp.Header.Get("Content-Type")View on GitHub (pinned to 7944b8e522)
Solutions
- Check the wrapped error: EEXIST on a path component means a file occupies a directory slot — choose a different file_path
- Verify write permissions on the destination directory (ls -ld)
- Ensure the download target is inside the writable working directory
- Free disk space or remount read-only filesystems as writable
Example fix
// before file_path: "out.txt/data.zip" // out.txt is an existing file // after file_path: "downloads/data.zip"
Defensive patterns
Strategy: validation
Validate before calling
parent := filepath.Dir(target)
if fi, err := os.Stat(parent); err == nil && !fi.IsDir() {
return fmt.Errorf("%s exists and is not a directory", parent)
}
if err := unix.Access(filepath.Dir(parent), unix.W_OK); err != nil {
return fmt.Errorf("no write permission for %s: %v", parent, err)
} Try / catch
if err := os.MkdirAll(dir, 0o755); err != nil {
if errors.Is(err, fs.ErrExist) {
return fmt.Errorf("a file occupies a directory path component: %s", dir)
}
if errors.Is(err, fs.ErrPermission) {
return fmt.Errorf("cannot write to %s: %w", dir, err)
}
return err
} Prevention
- Choose a file_path whose parent directories don't collide with existing files
- Keep downloads inside the writable working directory
- Check df/mount options when targeting containers or network mounts
When it happens
Trigger: The directory portion of workingDir + params.FilePath cannot be created: a parent path component is an existing regular file, the process lacks write permission, or the filesystem is read-only/full.
Common situations: file_path points under a path where a file already occupies a directory name (e.g. /tmp/out.txt/sub/dir); downloading into a read-only mount or container layer; destination inside a directory owned by another user.
Related errors
- failed to create parent directories: %w
- error creating directory: %w
- failed to create data directory: %q %w
- failed to create output file: %w
- failed to access file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/b0c8e83713fc34f0.
Report an issue: GitHub.