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 client

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Treat as an internal bug: capture engine logs/trace and report
  2. Avoid invoking paths needing the main conn during shutdown
  3. Check newer Dagger versions for race fixes
  4. 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

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


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