dagger/dagger · error
session %q not initialized
Error message
session %q not initialized
What it means
The session ID exists in the registry but its lifecycle state is still sessionStateUninitialized, meaning it has been registered but its session-level initialization has not completed. The server refuses to hand out clients from a not-yet-initialized session rather than racing with initialization.
Source
Thrown at engine/server/session.go:1125
// where for instance the first client cancels and closes its session while others
// are waiting on the result. In this case its safe to retry the operation again with
// the still connected client metadata.
err := flightcontrol.RetryableError{Err: fmt.Errorf("session %q not found", sessID)}
return nil, err
}
// Gate on the session's lifecycle state via a lock-free atomic read (never
// lifecycleMu), so this lookup can't block on a session that is initializing
// or tearing down. A client is inserted into sess.clients only after it is
// fully initialized, so a clientMu read can't observe a half-initialized one.
switch st := sess.state.Load(); st {
case sessionStateInitialized:
// continue
case sessionStateRemoved:
err := flightcontrol.RetryableError{Err: fmt.Errorf("session %q not found", sessID)}
return nil, err
case sessionStateUninitialized:
return nil, fmt.Errorf("session %q not initialized", sessID)
default:
return nil, fmt.Errorf("session %q has unknown state %s", sessID, st)
}
sess.clientMu.RLock()
client, ok := sess.clients[clientID]
sess.clientMu.RUnlock()
if !ok {
return nil, fmt.Errorf("client %q not found", clientID)
}
// Re-check state: if the session flipped to removed while we read the clients
// map, treat it as not-found rather than handing back a client whose session
// is tearing down. This is a lock-free atomic read, so it never blocks.
if sess.state.Load() == sessionStateRemoved {
return nil, flightcontrol.RetryableError{Err: fmt.Errorf("session %q not found", sessID)}
}
View on GitHub (pinned to 82ba2681db)
Solutions
- Retry after a short delay — initialization is in progress and will mark the session initialized
- Ensure all calls for a session go through getOrInitClient, not raw lookups, when the session may be new
- Serialize the first call of a session in client code before fanning out concurrent operations
- Report as a bug if persistent — the state machine should make this window unreachable for normal clients
Defensive patterns
Strategy: retry
Validate before calling
if !sessionReady(sessID) { time.Sleep(50 * time.Millisecond) } Type guard
func isNotInitializedErr(err error) bool { return err != nil && strings.Contains(err.Error(), "not initialized") } Try / catch
if err := op(ctx); err != nil {
if strings.Contains(err.Error(), "session %q not initialized") { return retryUntilInitialized(op) }
return err
} Prevention
- Route all calls for a session through getOrInitClient, not raw lookups
- Serialize the session's first call before fanning out concurrent operations
- Retry briefly when racing a brand-new session's initialization
When it happens
Trigger: A lookup (clientFromIDs/clientFromContext) races with getOrInitClient: another goroutine created the session entry but is still inside initializeDaggerSession; observation of the registry before initialization finishes.
Common situations: Concurrent first calls into a brand-new session where one path observes the raw session; instrumentation or internal calls that hit clientFromIDs before the main client finished connecting.
Related errors
- initialize session: %w
- failed to get current query: %w
- failed to get main client caller ID: %w
- current served deps: %w
- failed to get dag for go module sdk client generation: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/add0c2a9af903205.
Report an issue: GitHub.