dagger/dagger · error

acquire cache volume snapshot %q: opened snapshot %q

Error message

acquire cache volume snapshot %q: opened snapshot %q

What it means

cacheVolumeStore.acquire (core/cache.go) opens a cache volume snapshot by ID and validates that the MutableRef returned by the open callback reports the same SnapshotID. This error means the opened ref's snapshot ID differs from the requested one, so the ref is released and acquire fails to prevent sharing the wrong snapshot. It guards an internal invariant between the requested ID and the snapshotter's answer.

Source

Thrown at core/cache.go:234

	if s.entries == nil {
		s.entries = make(map[string]*cacheVolumeStoreEntry)
	}
	if entry, ok := s.entries[snapshotID]; ok {
		entry.refs++
		return entry.ref, (&cacheVolumeStoreReleaser{store: s, snapshotID: snapshotID}).release, nil
	}

	ref, err := open(ctx)
	if err != nil {
		return nil, nil, err
	}
	if ref == nil {
		return nil, nil, fmt.Errorf("acquire cache volume snapshot %q: nil mutable ref", snapshotID)
	}
	if ref.SnapshotID() != snapshotID {
		_ = ref.Release(context.WithoutCancel(ctx))
		return nil, nil, fmt.Errorf("acquire cache volume snapshot %q: opened snapshot %q", snapshotID, ref.SnapshotID())
	}

	s.entries[snapshotID] = &cacheVolumeStoreEntry{
		ref:  ref,
		refs: 1,
	}
	return ref, (&cacheVolumeStoreReleaser{store: s, snapshotID: snapshotID}).release, nil
}

func (s *cacheVolumeStore) register(ctx context.Context, ref bkcache.MutableRef) (func(context.Context) error, error) {
	if ref == nil {
		return nil, fmt.Errorf("register cache volume snapshot: nil mutable ref")
	}
	snapshotID := ref.SnapshotID()
	if snapshotID == "" {
		_ = ref.Release(context.WithoutCancel(ctx))
		return nil, fmt.Errorf("register cache volume snapshot: empty snapshot ID")
	}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Fix the open callback so it opens the snapshot for exactly the requested snapshotID.
  2. Restart/upgrade the Dagger engine to rule out snapshotter state corruption.
  3. If using mocks in tests, make SnapshotID() return the requested ID.
  4. Check for concurrent delete/recreate of the snapshot and serialize the acquire path.

Example fix

// before (mock opens arbitrary snapshot)
open := func(ctx context.Context) (bkcache.MutableRef, error) { return arbitraryRef, nil }
// after
open := func(ctx context.Context) (bkcache.MutableRef, error) { return snap.GetRef(ctx, snapshotID) }
Defensive patterns

Strategy: validation

Validate before calling

if ref == nil || ref.SnapshotID() != snapshotID {
    return fmt.Errorf("open callback returned snapshot %q, want %q", refSafeID(ref), snapshotID)
}

Type guard

func refMatchesSnapshot(ref bkcache.MutableRef, id string) bool {
    return ref != nil && ref.SnapshotID() == id
}

Try / catch

ref, rel, err := store.acquire(ctx, snapshotID, open)
if err != nil {
    var mismatchErr *fmt.WrapError // log and fall back to re-opening
    return fmt.Errorf("acquire failed: %w", err)
}

Prevention

When it happens

Trigger: Calling acquire (via the cache volume attach path) where open(ctx) returns a ref for a different snapshot than the requested snapshotID — e.g. a snapshotter returning a recycled/recreated snapshot, or a mocked open function returning the wrong ref.

Common situations: Running against a modified or buggy containerd snapshotter; engine races where the snapshot is deleted and re-created between ID derivation and open; test doubles that do not honor the requested snapshot ID.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/44b410dd7234a7b9. Report an issue: GitHub.