dagger/dagger · error

load persisted %s snapshot links query: %w

Error message

load persisted %s snapshot links query: %w

What it means

Wraps failures from persistedDecodeQuery, which extracts the *Query from the dagql server's root object. This error means the dagql server passed to DecodePersistedObject is nil, has a nil root, or its root is not a *Query, so persisted snapshot links cannot be loaded.

Source

Thrown at core/persisted_object.go:144

	}
	links, err := cache.PersistedSnapshotLinksByResultID(ctx, resultID)
	if err != nil {
		return dagql.PersistedSnapshotRefLink{}, fmt.Errorf("load persisted %s snapshot link: %w", label, err)
	}
	for _, link := range links {
		if link.Role == role {
			return link, nil
		}
	}
	return dagql.PersistedSnapshotRefLink{}, fmt.Errorf("missing persisted %s snapshot link role %q for result %d", label, role, resultID)
}

func loadPersistedSnapshotLinksByResultID(ctx context.Context, dag *dagql.Server, resultID uint64, label string) ([]dagql.PersistedSnapshotRefLink, error) {
	if resultID == 0 {
		return nil, fmt.Errorf("load persisted %s snapshot links: zero result ID", label)
	}
	if _, err := persistedDecodeQuery(dag); err != nil {
		return nil, fmt.Errorf("load persisted %s snapshot links query: %w", label, err)
	}
	cache, err := dagql.EngineCache(ctx)
	if err != nil {
		return nil, fmt.Errorf("load persisted %s snapshot links cache: %w", label, err)
	}
	links, err := cache.PersistedSnapshotLinksByResultID(ctx, resultID)
	if err != nil {
		return nil, fmt.Errorf("load persisted %s snapshot links: %w", label, err)
	}
	return links, nil
}

func loadPersistedImmutableSnapshotByResultID(ctx context.Context, dag *dagql.Server, resultID uint64, label, role string) (bkcache.ImmutableRef, error) {
	link, err := loadPersistedSnapshotLinkByResultID(ctx, dag, resultID, label, role)
	if err != nil {
		return nil, err
	}
	query, err := persistedDecodeQuery(dag)

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Ensure the dagql.Server passed to decode functions was created with the engine's *Query as its root object.
  2. Check for nil before calling: verify dag and dag.Root() are non-nil.
  3. If running in a test harness, construct the server the same way the engine does (root *Query) instead of a stub.

Example fix

// before
srv := dagql.NewServer(myCustomRoot{}) // root is not *Query
obj, err := DecodePersistedObject(ctx, srv, payload)
// after
srv := dagql.NewServer(query) // query is *core.Query
obj, err := DecodePersistedObject(ctx, srv, payload)
Defensive patterns

Strategy: try-catch

Validate before calling

if dag == nil || dag.Root() == nil {
    return fmt.Errorf("dagql server not initialized")
}

Type guard

if q, ok := dagql.UnwrapAs[*core.Query](dag.Root()); ok {
    // root is a *Query, safe to decode
}

Try / catch

obj, err := DecodePersistedObject(ctx, dag, payload)
if err != nil && strings.Contains(err.Error(), "persisted decode query") {
    // server root is not *Query; re-init server with Query root
}

Prevention

When it happens

Trigger: loadPersistedSnapshotLinksByResultID is called (via DecodePersistedObject) with a dag server whose root object was not constructed as *Query — e.g. a test server rooted at a different object, or a nil server passed in.

Common situations: Tests spinning up a dagql.Server with a custom root type; calling decode helpers before the engine finishes initializing the root query; refactoring that changed the root object type.

Related errors


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