charmbracelet/crush · error

failed to save Hyper provider to cache: %w

Error message

failed to save Hyper provider to cache: %w

What it means

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).

Source

Thrown at internal/config/provider.go:142

			resolveKey: func() string { return resolveHyperAPIKey(nil) },
		}
		var err error
		provider, err = client.Get(context.Background(), "")
		if err != nil {
			return fmt.Errorf("failed to fetch provider from Hyper: %w", err)
		}
	default:
		content, err := os.ReadFile(pathOrURL)
		if err != nil {
			return fmt.Errorf("failed to read file: %w", err)
		}
		if err := json.Unmarshal(content, &provider); err != nil {
			return fmt.Errorf("failed to unmarshal provider data: %w", err)
		}
	}

	if err := newCache[catwalk.Provider](cachePathFor("hyper")).Store(provider); err != nil {
		return fmt.Errorf("failed to save Hyper provider to cache: %w", err)
	}

	slog.Info("Hyper provider updated successfully", "from", pathOrURL, "to", cachePathFor("hyper"))
	return nil
}

var (
	catwalkSyncer = &catwalkSync{}
	hyperSyncer   = &hyperSync{}
)

// Providers returns the list of providers, taking into account cached results
// and whether or not auto update is enabled.
//
// It will:
// 1. if auto update is disabled, it'll return the embedded providers at the
// time of release.
// 2. load the cached providers

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check permissions and free space on the cache directory (`ls -ld`, `df -h`).
  2. Set XDG_CACHE_HOME to a writable directory.
  3. Remove a corrupt/partial hyper cache file and retry.
  4. In containers, mount a writable volume at the cache path.

Example fix

// before
docker run -v /ro-cache:/root/.cache crush update-hyper
// after
docker run -v writable:/root/.cache crush update-hyper
Defensive patterns

Strategy: try-catch

Validate before calling

hyperCache := cachePathFor("hyper")
if err := os.MkdirAll(filepath.Dir(hyperCache), 0o755); err != nil {
    return fmt.Errorf("cannot create hyper cache dir: %w", err)
}
probe, _ := os.CreateTemp(filepath.Dir(hyperCache), "writetest")
probe.Close(); os.Remove(probe.Name())

Try / catch

if err := config.UpdateHyper(src); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.EACCES) || errors.Is(pe.Err, syscall.ENOSPC)) {
        slog.Error("cannot write hyper cache", "path", pe.Path, "err", pe.Err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/496341087b38c658. Report an issue: GitHub.