{"record":{"id":"496341087b38c658","repo":"charmbracelet/crush","slug":"failed-to-save-hyper-provider-to-cache-w","errorCode":null,"errorMessage":"failed to save Hyper provider to cache: %w","messagePattern":"failed to save Hyper provider to cache: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/provider.go","lineNumber":142,"sourceCode":"\t\t\tresolveKey: func() string { return resolveHyperAPIKey(nil) },\n\t\t}\n\t\tvar err error\n\t\tprovider, err = client.Get(context.Background(), \"\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch provider from Hyper: %w\", err)\n\t\t}\n\tdefault:\n\t\tcontent, err := os.ReadFile(pathOrURL)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read file: %w\", err)\n\t\t}\n\t\tif err := json.Unmarshal(content, &provider); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal provider data: %w\", err)\n\t\t}\n\t}\n\n\tif err := newCache[catwalk.Provider](cachePathFor(\"hyper\")).Store(provider); err != nil {\n\t\treturn fmt.Errorf(\"failed to save Hyper provider to cache: %w\", err)\n\t}\n\n\tslog.Info(\"Hyper provider updated successfully\", \"from\", pathOrURL, \"to\", cachePathFor(\"hyper\"))\n\treturn nil\n}\n\nvar (\n\tcatwalkSyncer = &catwalkSync{}\n\thyperSyncer   = &hyperSync{}\n)\n\n// Providers returns the list of providers, taking into account cached results\n// and whether or not auto update is enabled.\n//\n// It will:\n// 1. if auto update is disabled, it'll return the embedded providers at the\n// time of release.\n// 2. load the cached providers","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/provider.go#L124-L160","documentation":"UpdateHyper persists the resolved provider via newCache[catwalk.Provider](cachePathFor(\"hyper\")).Store. This error wraps cache-write failures: missing/unwritable cache directory, disk full, permission denied, or an atomic rename failure (including Windows ERROR_ACCESS_DENIED).","triggerScenarios":"Calling config.UpdateHyper when the cache location for \"hyper\" cannot be created or written: read-only HOME/XDG_CACHE_HOME, full disk, sandboxed container without writable cache, or antivirus locking the temp file on Windows.","commonSituations":"Read-only home directory in CI; disk quota exceeded; container running as non-root with a mounted read-only cache volume; concurrent runs racing on the same cache file.","solutions":["Check permissions and free space on the cache directory (`ls -ld`, `df -h`).","Set XDG_CACHE_HOME to a writable directory.","Remove a corrupt/partial hyper cache file and retry.","In containers, mount a writable volume at the cache path."],"exampleFix":"// before\ndocker run -v /ro-cache:/root/.cache crush update-hyper\n// after\ndocker run -v writable:/root/.cache crush update-hyper","handlingStrategy":"try-catch","validationCode":"hyperCache := cachePathFor(\"hyper\")\nif err := os.MkdirAll(filepath.Dir(hyperCache), 0o755); err != nil {\n    return fmt.Errorf(\"cannot create hyper cache dir: %w\", err)\n}\nprobe, _ := os.CreateTemp(filepath.Dir(hyperCache), \"writetest\")\nprobe.Close(); os.Remove(probe.Name())","typeGuard":null,"tryCatchPattern":"if err := config.UpdateHyper(src); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.EACCES) || errors.Is(pe.Err, syscall.ENOSPC)) {\n        slog.Error(\"cannot write hyper cache\", \"path\", pe.Path, \"err\", pe.Err)\n    }\n    return err\n}","preventionTips":["Mount a writable volume at the cache path in containers.","Set XDG_CACHE_HOME explicitly in CI and sandboxed environments.","Clean up stale/partial hyper cache files after crashed runs.","Avoid running concurrent UpdateHyper processes against the same cache."],"tags":["filesystem","cache","disk","persistence"],"backgroundTag":"cache-write-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}