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
- Fix the open callback so it opens the snapshot for exactly the requested snapshotID.
- Restart/upgrade the Dagger engine to rule out snapshotter state corruption.
- If using mocks in tests, make SnapshotID() return the requested ID.
- 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
- Always open snapshots by the exact requested ID in open callbacks
- Keep mock snapshotters faithful: SnapshotID() must echo the requested ID
- Pin and test against the engine's expected containerd/snapshotter version
- Watch for concurrent snapshot deletion/recreation around acquire
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
- register cache volume snapshot: empty snapshot ID
- register cache volume snapshot: nil mutable ref
- register cache volume snapshot %q: already registered
- encode persisted cache volume: nil cache volume
- marshal persisted cache volume payload: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/44b410dd7234a7b9.
Report an issue: GitHub.