lima-vm/lima · error

caching-only mode requires the cache directory to be specifi

Error message

caching-only mode requires the cache directory to be specified

What it means

The downloader was invoked in caching-only mode (no local output path) but the Options were never given a cache directory, so there is nowhere to store or find the downloaded artifact. Download refuses to proceed rather than guessing a location.

Source

Thrown at pkg/downloader/downloader.go:199

// Download downloads the remote resource into the local path.
//
// Download caches the remote resource if WithCache or WithCacheDir option is specified.
// Local files are not cached.
//
// When the local path already exists, Download returns Result with StatusSkipped.
// (So, the local path cannot be set to /dev/null for "caching only" mode.)
//
// The local path can be an empty string for "caching only" mode.
func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, error) {
	var o options
	if err := o.apply(opts); err != nil {
		return nil, err
	}

	var localPath string
	if local == "" {
		if o.cacheDir == "" {
			return nil, errors.New("caching-only mode requires the cache directory to be specified")
		}
	} else {
		var err error
		localPath, err = canonicalLocalPath(local)
		if err != nil {
			return nil, err
		}
		if _, err := os.Stat(localPath); err == nil {
			logrus.Debugf("file %#q already exists, skipping downloading from %#q (and skipping digest validation)", localPath, remote)
			res := &Result{
				Status:          StatusSkipped,
				ValidatedDigest: false,
			}
			return res, nil
		} else if !errors.Is(err, os.ErrNotExist) {
			return nil, err
		}

View on GitHub (pinned to dd909d0973)

Solutions

  1. Set CacheDir (e.g. ~/.cache/lima) in the downloader Options before calling Download.
  2. Pass a non-empty local path if you actually want a direct download instead of cache-only mode.
  3. Review the code path that constructs the Options to ensure the cache-dir flag/env (e.g. LIMA_HOME) is propagated.

Example fix

// before
opts := &downloader.Options{}
res, err := opts.Download(ctx, "", "https://example.com/img.iso")
// after
opts := &downloader.Options{CacheDir: filepath.Join(home, ".cache", "lima")}
res, err := opts.Download(ctx, "", "https://example.com/img.iso")
Defensive patterns

Strategy: validation

Validate before calling

if o.CacheDir == "" && local == "" {
    return errors.New("cache-only download requires Options.CacheDir to be set")
}

Try / catch

res, err := d.Download(ctx, local, url)
if err != nil && strings.Contains(err.Error(), "cache directory to be specified") {
    return fmt.Errorf("configure CacheDir in downloader options: %w", err)
}

Prevention

When it happens

Trigger: Calling downloader.Download with local=="" while opts.cacheDir is empty — typically via DownloadFile or direct Download calls that omit CacheDir in the downloader Options and pass an empty local path.

Common situations: Constructing downloader.New() without setting CacheDir but intending cache-only lookups; tests/utilities that pass "" for local to mean "just use the cache".

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/6a38e9b0faf1a579. Report an issue: GitHub.