{"record":{"id":"c3a5b0ff6ff60983","repo":"charmbracelet/crush","slug":"failed-to-create-directory-for-provider-cache-w","errorCode":null,"errorMessage":"failed to create directory for provider cache: %w","messagePattern":"failed to create directory for provider cache: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/provider.go","lineNumber":287,"sourceCode":"\nfunc (c cache[T]) Get() (T, string, error) {\n\tvar v T\n\tdata, err := os.ReadFile(c.path)\n\tif err != nil {\n\t\treturn v, \"\", fmt.Errorf(\"failed to read provider cache file: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(data, &v); err != nil {\n\t\treturn v, \"\", fmt.Errorf(\"failed to unmarshal provider data from cache: %w\", err)\n\t}\n\n\treturn v, etag.Of(data), nil\n}\n\nfunc (c cache[T]) Store(v T) error {\n\tslog.Info(\"Saving provider data to disk\", \"path\", c.path)\n\tif err := os.MkdirAll(filepath.Dir(c.path), 0o755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create directory for provider cache: %w\", err)\n\t}\n\n\tdata, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal provider data: %w\", err)\n\t}\n\n\t// Written through a temporary file and renamed into place. Several Crush\n\t// instances start independently and race to refresh this cache, and a\n\t// truncating write would let one of them read a half-written catalog and\n\t// silently fall back to the bundled copy.\n\tif err := atomicWriteFile(c.path, data, 0o644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write provider data to cache: %w\", err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":269,"sourceCodeEnd":304,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/provider.go#L269-L304","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nexport XDG_CACHE_HOME=/mnt/readonly/cache\n// after\nexport XDG_CACHE_HOME=$HOME/.cache","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(cachePath)\nif info, err := os.Stat(dir); err == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := cache.Store(v); err != nil {\n    if errors.Is(err, fs.ErrPermission) {\n        slog.Warn(\"Cache dir unwritable; using in-memory providers\")\n    }\n}","preventionTips":["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"],"tags":["filesystem","permissions","cache"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}