charmbracelet/crush · error

failed to write provider data to cache: %w

Error message

failed to write provider data to cache: %w

What it means

Thrown by cache.Store() when the atomic write (temp file + rename via atomicWriteFile) fails to persist the marshaled provider data. The atomic design protects concurrent Crush instances from reading a half-written cache, but the final write/rename can still fail at the OS level.

Source

Thrown at internal/config/provider.go:300

}

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

  1. Free disk space / check quota (df -h) on the cache volume.
  2. Fix permissions on the cache directory and existing cache file.
  3. Ensure the path and its temp file are on the same filesystem so rename succeeds.
  4. Check for mandatory access control denials (audit logs) and adjust policy.
  5. Retry the update once the filesystem issue is resolved; the previous cache remains intact.

Example fix

// before
Store(providers) // ENOSPC
// after
df -h ~/.cache/crush  # free space, then retry
crush update-providers
Defensive patterns

Strategy: retry

Validate before calling

dir := filepath.Dir(cachePath)
if err := unix.Access(dir, unix.W_OK); err != nil { /* warn: unwritable */ }
// also check free space periodically

Try / catch

err := cache.Store(v)
for i := 0; err != nil && i < 3; i++ {
    time.Sleep(100 * time.Millisecond)
    err = cache.Store(v)
}

Prevention

When it happens

Trigger: atomicWriteFile(c.path, data, 0o644) fails: disk full (ENOSPC), permission denied on the target directory or existing file, the temp file cannot be created/renamed (cross-device), or the filesystem is read-only.

Common situations: Quota exceeded on the cache volume; read-only filesystem after mount remount; concurrent writers on a filesystem where rename semantics differ; SELinux/AppArmor denial.

Related errors


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