charmbracelet/crush · error
failed to create data directory
Error message
failed to create data directory: %q %w
What it means
createDotCrushDir creates the workspace data directory (mode 0700) and this error wraps os.MkdirAll failure. The quoted %q shows exactly which directory path could not be created, alongside the underlying OS error. It aborts workspace creation because subsequent data (DB, config) cannot live without the directory.
Solutions
- Read the quoted path and underlying OS error to identify permission vs existence issues.
- If a regular file occupies the path, remove or rename it and retry.
- Check write permission on the parent directory (ls -ld on each component).
- Choose a different data directory on a writable filesystem.
Example fix
// before
// crash on read-only HOME
createDotCrushDir(filepath.Join(os.Getenv("HOME"), ".crush"))
// after
// pick a writable location explicitly
dir := os.Getenv("CRUSH_DATA_DIR")
if dir == "" {
dir = filepath.Join(os.TempDir(), "crush-data")
}
err := createDotCrushDir(dir) Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(dir); err == nil {
if !fi.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
}
parent := filepath.Dir(dir)
if fi, err := os.Stat(parent); err != nil || !fi.IsDir() {
return fmt.Errorf("parent %s missing", parent)
}
if err := unix.Access(parent, unix.W_OK); err != nil {
return fmt.Errorf("parent %s not writable: %w", parent, err)
} Type guard
func IsMkdirErr(err error) (string, bool) {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrExist) || errors.Is(err, fs.ErrPermission) {
return pe.Path, true
}
return "", false
} Try / catch
if err := createDotCrushDir(dir); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {
// fall back to a writable data dir
return createDotCrushDir(filepath.Join(os.TempDir(), "crush"))
}
return err
} Prevention
- Verify the target path is not an existing regular file before creating.
- Run the process as a user with write access to the chosen data location.
- Avoid read-only mounts (containers, CI) for data directories; use a volume or env override.
- Set HOME/CRUSH data dir explicitly in sandboxed environments.
When it happens
Trigger: Calling CreateWorkspace (indirectly via createDotCrushDir) when os.MkdirAll(dir, 0o700) fails — parent path doesn't exist and can't be created, permission denied on a parent, the path exists as a regular file, or the filesystem is read-only.
Common situations: Pointing the data dir at a read-only mount (containers, CI sandboxes); a file named .crush already exists where a directory is expected; running as a user without write access to the parent directory; HOME unset or mispointed.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- error creating directory
- error checking file
- error writing file
- failed to create .gitignore file
- failed to create parent directories
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/d243dd32b235593d.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/util.go:11
package backend
import (
"fmt"
"os"
"path/filepath"
)
func createDotCrushDir(dir string) error {
if err := os.MkdirAll(dir, 0o700); err != nil {
return fmt.Errorf("failed to create data directory: %q %w", dir, err)
}
gitIgnorePath := filepath.Join(dir, ".gitignore")
if _, err := os.Stat(gitIgnorePath); os.IsNotExist(err) {
if err := os.WriteFile(gitIgnorePath, []byte("*\n"), 0o644); err != nil {
return fmt.Errorf("failed to create .gitignore file: %q %w", gitIgnorePath, err)
}
}
return nil
}
View on GitHub (pinned to 7944b8e522)