dagger/dagger · error

get or init call: empty session ID

Error message

get or init call: empty session ID

What it means

Cache.getOrInitCall requires a non-empty session ID because results are scoped per client session. When it is called with an empty session ID, dagql rejects the call immediately rather than caching it under an anonymous session. A companion wrap ('get or init call: %w') covers failures from the session operation setup or the nested call.

Source

Thrown at dagql/cache.go:4267

		res.cacheUsageRecordTypeByID = recordTypeByIdentity

		recordTypes := cacheUsageRecordTypesFromMap(recordTypeByIdentity)
		if len(recordTypes) > 0 {
			res.recordType = cacheUsagePrimaryRecordType(recordTypes, "")
		}
	}
}

// Core cache lookup/insert flow is intentionally centralized here.
func (c *Cache) GetOrInitCall(
	ctx context.Context,
	sessionID string,
	resolver TypeResolver,
	req *CallRequest,
	fn func(context.Context) (AnyResult, error),
) (AnyResult, error) {
	if sessionID == "" {
		return nil, errors.New("get or init call: empty session ID")
	}
	op, err := c.beginSessionOperation(sessionID)
	if err != nil {
		return nil, fmt.Errorf("get or init call: %w", err)
	}
	res, callErr := c.getOrInitCall(ctx, sessionID, resolver, req, fn)
	if op.finish(callErr == nil && res != nil) {
		return nil, fmt.Errorf("get or init call: %w: %q", ErrCacheSessionReleased, sessionID)
	}
	return res, callErr
}

func (c *Cache) getOrInitCall(
	ctx context.Context,
	sessionID string,
	resolver TypeResolver,
	req *CallRequest,
	fn func(context.Context) (AnyResult, error),

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Ensure a valid session ID is passed: obtain it from engine.ClientMetadata(ctx) and fail fast if it's empty before calling the cache.
  2. Set up a client session (as the engine does per client connection) before issuing calls.
  3. In tests, populate a fake session ID in context metadata.
  4. Check that custom plumbing doesn't drop the session ID when constructing CallRequest.

Example fix

// before
res, err := cache.GetOrInitCall(ctx, "", resolver, req, fn)

// after
meta, err := engine.ClientMetadataFromContext(ctx)
if err != nil || meta.SessionID == "" {
	return nil, errors.New("no client session for call")
}
res, err := cache.GetOrInitCall(ctx, meta.SessionID, resolver, req, fn)
Defensive patterns

Strategy: validation

Validate before calling

meta, err := engine.ClientMetadataFromContext(ctx)
if err != nil || meta.SessionID == "" {
	return errors.New("client session required before calling the cache")
}

Try / catch

if _, err := cache.GetOrInitCall(ctx, sessionID, resolver, req, fn); err != nil {
	if strings.Contains(err.Error(), "empty session ID") {
		return fmt.Errorf("missing client session: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling GetOrInitCall/getOrInitCall with sessionID == "" — e.g. client metadata missing from the context when the session ID was extracted; constructing CallRequests outside a client session; SDK plumbing that fails to propagate the session header.

Common situations: Embedded dagger usage invoking the GraphQL layer without a client session; tests hitting the cache directly without setting up a session; upgrades where session metadata moved in the context and code reads the old key.

Related errors


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