lima-vm/lima · error

failed to open raw tmp file %q: %w

Error message

failed to open raw tmp file %q: %w

What it means

After successfully converting the image to rawPathTmp, ensureRawInCache reopens the temp file with os.OpenFile(O_RDWR) to sparsify it. If opening fails, this error wraps the OS error. Failure here means the conversion result exists but cannot be finalized.

Source

Thrown at pkg/downloader/downloader.go:482

func ensureRawInCache(ctx context.Context, imagePath, format string, originalDigest digest.Digest) (string, digest.Digest, error) {
	imgConvPath := filepath.Join(filepath.Dir(imagePath), "imgconv")
	if err := os.MkdirAll(imgConvPath, 0o700); err != nil {
		return "", "", err
	}
	rawImgConvPath := filepath.Join(imgConvPath, "raw")

	logrus.Infof("Converting %s image to raw sparse format in cache: %q", format, rawImgConvPath)
	rawPathTmp := filepath.Join(imgConvPath, "raw.tmp")
	defer os.Remove(rawPathTmp)
	diskUtil := proxyimgutil.NewDiskUtil(ctx)
	if err := diskUtil.Convert(ctx, raw.Type, imagePath, rawPathTmp, nil, false); err != nil {
		return "", "", fmt.Errorf("failed to convert %q to raw: %w", imagePath, err)
	}

	// Ensure the image is sparse to save cache space.
	rawTmpF, err := os.OpenFile(rawPathTmp, os.O_RDWR, 0o644)
	if err != nil {
		return "", "", fmt.Errorf("failed to open raw tmp file %q: %w", rawPathTmp, err)
	}
	fi, err := rawTmpF.Stat()
	if err != nil {
		_ = rawTmpF.Close()
		return "", "", fmt.Errorf("failed to stat raw tmp file %q: %w", rawPathTmp, err)
	}
	if err := diskUtil.MakeSparse(ctx, rawTmpF, fi.Size()); err != nil {
		logrus.WithError(err).Warnf("Failed to make %q sparse (non-fatal)", rawPathTmp)
	}
	if err := rawTmpF.Close(); err != nil {
		return "", "", fmt.Errorf("failed to close raw tmp file %q: %w", rawPathTmp, err)
	}

	if err := os.Remove(rawImgConvPath); err != nil && !errors.Is(err, os.ErrNotExist) {
		return "", "", fmt.Errorf("failed to remove stale raw image %q: %w", rawImgConvPath, err)
	}
	if err := os.Rename(rawPathTmp, rawImgConvPath); err != nil {
		return "", "", fmt.Errorf("failed to replace original with raw image: %w", err)

View on GitHub (pinned to dd909d0973)

Solutions

  1. Check ownership/permissions of the cache directory and the imgConv subdir; fix with chown/chmod.
  2. Ensure only one download for the same image runs at a time, or clean the cache of stale raw.tmp files.
  3. Move the cache to a writable local filesystem (adjust CacheDir).

Example fix

// before: root-owned cache
$ sudo chown -R $(id -u):$(id -g) ~/.cache/lima
$ rm -f ~/.cache/lima/images/*/raw.tmp
// after: reopen succeeds, sparsification proceeds
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(cacheDir)
if err != nil || !info.IsDir() {
    return fmt.Errorf("cache dir not writable: %w", err)
}
if err := unix.Access(cacheDir, unix.W_OK); err != nil {
    return fmt.Errorf("cache dir lacks write permission: %w", err)
}

Try / catch

res, err := d.Download(ctx, local, url)
if err != nil && strings.Contains(err.Error(), "failed to open raw tmp file") {
    // fix cache ownership/permissions, remove stale raw.tmp, retry
}

Prevention

When it happens

Trigger: os.OpenFile(rawPathTmp, os.O_RDWR, 0o644) fails right after conversion — typically permission problems on the cache dir, the file being locked/removed by a concurrent process, or a read-only mount.

Common situations: Cache shared between users/VMs with mixed ownership; concurrent limactl downloads racing on the same cache entry; containers running as non-root against a root-owned cache.

Related errors


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