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
- Ensure a valid session ID is passed: obtain it from engine.ClientMetadata(ctx) and fail fast if it's empty before calling the cache.
- Set up a client session (as the engine does per client connection) before issuing calls.
- In tests, populate a fake session ID in context metadata.
- 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
- Extract session IDs from client metadata and validate before cache calls.
- Never invoke the GraphQL/cache layer outside a client session in tests or embedded use.
- Keep session metadata propagation intact through custom SDK plumbing.
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
- lookup call request: empty session ID
- lookup call request: type resolver is nil
- failed parsing [%s], expected address format: [%s]
- use target SDK language: %s: %w
- unmarshal introspection json: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/0ede3f45eec16d72.
Report an issue: GitHub.