charmbracelet/crush · error
failed to create directory for provider cache: %w
Error message
failed to create directory for provider cache: %w
What it means
Thrown by cache.Store() when os.MkdirAll cannot create the parent directory of the cache path. The cache layer requires the directory to exist before writing the temp file, so a filesystem-level failure (permissions, read-only mount, path is a file) aborts the store.
Source
Thrown at internal/config/provider.go:287
func (c cache[T]) Get() (T, string, error) {
var v T
data, err := os.ReadFile(c.path)
if err != nil {
return v, "", fmt.Errorf("failed to read provider cache file: %w", err)
}
if err := json.Unmarshal(data, &v); err != nil {
return v, "", fmt.Errorf("failed to unmarshal provider data from cache: %w", err)
}
return v, etag.Of(data), nil
}
func (c cache[T]) Store(v T) error {
slog.Info("Saving provider data to disk", "path", c.path)
if err := os.MkdirAll(filepath.Dir(c.path), 0o755); err != nil {
return fmt.Errorf("failed to create directory for provider cache: %w", err)
}
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("failed to marshal provider data: %w", err)
}
// Written through a temporary file and renamed into place. Several Crush
// instances start independently and race to refresh this cache, and a
// truncating write would let one of them read a half-written catalog and
// silently fall back to the bundled copy.
if err := atomicWriteFile(c.path, data, 0o644); err != nil {
return fmt.Errorf("failed to write provider data to cache: %w", err)
}
return nil
}
View on GitHub (pinned to 7944b8e522)
Solutions
- Check permissions on the ancestor directories of the cache path and fix with chmod/chown.
- If a file exists where a directory is expected, remove/rename that file.
- Point the cache location to a writable directory (fix HOME/XDG_CACHE_HOME or the config path option).
- Ensure the container/mount is writable (rw mount, writable $HOME).
- Free disk space if the failure is ENOSPC.
Example fix
// before export XDG_CACHE_HOME=/mnt/readonly/cache // after export XDG_CACHE_HOME=$HOME/.cache
Defensive patterns
Strategy: validation
Validate before calling
dir := filepath.Dir(cachePath)
if info, err := os.Stat(dir); err == nil && !info.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
if err := os.MkdirAll(dir, 0o755); err != nil { return err } Try / catch
if err := cache.Store(v); err != nil {
if errors.Is(err, fs.ErrPermission) {
slog.Warn("Cache dir unwritable; using in-memory providers")
}
} Prevention
- Ensure HOME/XDG_CACHE_HOME point to writable directories
- Never place a regular file where the cache directory should be
- Mount container volumes read-write
- Check disk space and permissions before installing
When it happens
Trigger: Calling Store() (directly or via Init, fetch, UpdateProviders, UpdateHyper, etc.) where filepath.Dir(c.path) cannot be created: parent path component exists as a regular file, EACCES on the ancestor directory, or the filesystem is read-only (e.g. container with unwritable HOME).
Common situations: HOME or XDG_CACHE_HOME pointing to a read-only or non-existent mount; a file named like the cache directory blocks MkdirAll; running as a different user with restrictive umask; Docker images with non-writable $HOME.
Related errors
- failed to create server working directory: %v
- 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/c3a5b0ff6ff60983.
Report an issue: GitHub.