dagger/dagger · error

encode persisted cache volume: nil cache volume

Error message

encode persisted cache volume: nil cache volume

What it means

CacheVolume.EncodePersistedObject (core/cache.go:307) serializes a cache volume into a persisted-object payload for the dagql persistence layer; a nil *CacheVolume has nothing to encode, so it fails fast with this error. It is a defensive check against typed-nil receivers reaching persistence.

Source

Thrown at core/cache.go:310

	ref := entry.ref
	s.mu.Unlock()

	return ref.Release(ctx)
}

type persistedCacheVolumePayload struct {
	Key            string           `json:"key"`
	Namespace      string           `json:"namespace,omitempty"`
	SourceResultID uint64           `json:"sourceResultID,omitempty"`
	Sharing        CacheSharingMode `json:"sharing,omitempty"`
	Owner          string           `json:"owner,omitempty"`
	Selector       string           `json:"selector,omitempty"`
}

func (cache *CacheVolume) EncodePersistedObject(ctx context.Context, persistedCache dagql.PersistedObjectCache) (dagql.PersistedObjectEncoding, error) {
	_ = ctx
	if cache == nil {
		return dagql.PersistedObjectEncoding{}, fmt.Errorf("encode persisted cache volume: nil cache volume")
	}
	var sourceResultID uint64
	if cache.Source.Valid {
		encoded, err := encodePersistedObjectRef(persistedCache, cache.Source.Value, "cache volume source")
		if err != nil {
			return dagql.PersistedObjectEncoding{}, err
		}
		sourceResultID = encoded
	}
	cache.mu.Lock()
	selector := cache.selector
	if selector == "" {
		selector = "/"
	}
	snapshotID := cache.snapshotID
	var snapshotLinks []dagql.PersistedSnapshotRefLink
	if cache.snapshot != nil {
		snapshotID = cache.snapshot.SnapshotID()

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Construct the CacheVolume via NewCache(key, namespace, source, sharing, owner) before persistence.
  2. At the call site, skip persistence when the cache volume is nil.
  3. Ensure Nullable fields are only encoded when Valid.

Example fix

// before
enc, err := cache.EncodePersistedObject(ctx, persistedCache) // cache is nil
// after
if cache == nil {
    return dagql.PersistedObjectEncoding{}, fmt.Errorf("no cache volume to persist")
}
enc, err := cache.EncodePersistedObject(ctx, persistedCache)
Defensive patterns

Strategy: type-guard

Validate before calling

if cache == nil {
    return dagql.PersistedObjectEncoding{}, fmt.Errorf("cache volume not initialized")
}
enc, err := cache.EncodePersistedObject(ctx, persistedCache)

Type guard

func isPersistableCacheVolume(cv *CacheVolume) bool {
    return cv != nil && cv.Key != ""
}

Try / catch

enc, err := cache.EncodePersistedObject(ctx, persistedCache)
if err != nil {
    if strings.Contains(err.Error(), "nil cache volume") {
        // skip persistence or construct the volume here
    }
    return err
}

Prevention

When it happens

Trigger: Calling EncodePersistedObject on a nil *CacheVolume — e.g. an unset Nullable CacheVolume field being persisted, or a Go interface holding a typed nil pointer reaching the persistence path.

Common situations: Typed-nil through interfaces in engine code; query results where the cache volume was never constructed; stale/legacy persisted payloads decoded into nil objects.

Related errors


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