dagger/dagger · error
main client caller %q was nil
Error message
main client caller %q was nil
What it means
getClientCaller succeeded but returned a nil caller for the session's main client — an invariant violation, since the main client that created the session should always have a concrete caller. Defensive check against internal state bugs or teardown races.
Source
Thrown at engine/server/session.go:2725
}
return client.daggerSession.withClosingCancel(context.WithoutCancel(ctx)), nil
}
func (srv *Server) sessionMainClientConn(ctx context.Context, sess *daggerSession) (*grpc.ClientConn, error) {
_ = ctx
if sess == nil {
return nil, errors.New("session is nil")
}
client, err := srv.clientFromIDs(sess.sessionID, sess.mainClientCallerID)
if err != nil {
return nil, fmt.Errorf("failed to get main client %q: %w", sess.mainClientCallerID, err)
}
caller, err := client.getClientCaller(ctx, sess.mainClientCallerID)
if err != nil {
return nil, fmt.Errorf("failed to get main client caller %q: %w", sess.mainClientCallerID, err)
}
if caller == nil {
return nil, fmt.Errorf("main client caller %q was nil", sess.mainClientCallerID)
}
conn := caller.Conn()
if conn == nil {
return nil, fmt.Errorf("main client conn %q was nil", sess.mainClientCallerID)
}
return conn, nil
}
// The nearest ancestor client that is not a module (either a caller from the host like the CLI
// or a nested exec). Useful for figuring out where local sources should be resolved from through
// chains of dependency modules.
func (srv *Server) nonModuleParentClient(ctx context.Context) (*daggerClient, error) {
client, err := srv.clientFromContext(ctx)
if err != nil {
return nil, err
}
if client.mod.Self() == nil {
// not a module client, return the current clientView on GitHub (pinned to 82ba2681db)
Solutions
- Treat as an internal bug: capture engine logs/trace and report
- Avoid invoking paths needing the main conn during shutdown
- Check newer Dagger versions for race fixes
- Add defensive nil checks in forked code before use
Defensive patterns
Strategy: try-catch
Try / catch
conn, err := srv.sessionMainClientConn(ctx, sess)
if err != nil {
if strings.Contains(err.Error(), "was nil") {
// internal invariant violation: capture diagnostics
}
return err
} Prevention
- Treat nil callers as engine bugs and report with logs
- Serialize session teardown with conn resolution
- Add regression tests around main-client removal
When it happens
Trigger: sessionMainClientConn running while the main client's caller entry is being removed, or a registration path that stored a nil caller.
Common situations: Session shutdown racing with core API calls needing the main conn; engine bugs in caller registration order.
Related errors
- session is nil
- failed to get engine client: %w
- buildkit: %w
- failed to get engine cache for module context: %w
- get or init client: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/7f2930cce8a82370.
Report an issue: GitHub.