dagger/dagger · error

new client: %w

Error message

new client: %w

What it means

Wraps a failure of newBuildkitClient() at the end of startEngine — after the engine is provisioned, the client dials the engine's buildkit gRPC endpoint. Dial failures, TLS handshake errors, timeouts, or buildkit Info() RPC failures are wrapped here and abort the connect.

Source

Thrown at engine/client/client.go:505

		CloudAuth:        params.CloudAuth,
	})
	provisionCancel()
	telemetry.EndWithCause(provisionSpan, &err)
	if err != nil {
		return err
	}

	ctx, span := Tracer(ctx).Start(ctx, "connecting to engine", telemetry.Encapsulate())
	defer telemetry.EndWithCause(span, &rerr)

	slog := slog.SpanLogger(ctx, InstrumentationLibrary)
	slog.Debug("connecting", "runner", c.RunnerHost)

	bkCtx, span := Tracer(ctx).Start(ctx, "creating client")
	bkClient, bkInfo, err := newBuildkitClient(bkCtx, remote, c.connector)
	telemetry.EndWithCause(span, &err)
	if err != nil {
		return fmt.Errorf("new client: %w", err)
	}
	c.bkClient = bkClient
	c.bkVersion = bkInfo.BuildkitVersion.Version
	c.bkName = bkInfo.BuildkitVersion.Revision
	c.numCPU = bkInfo.SystemInfo.NumCPU

	slog.Info("connected", "name", c.bkName, "client-version", engine.Version, "server-version", c.bkVersion)

	imageBackend := c.ImageLoaderBackend
	if imageBackend == nil {
		imageBackend = driver.ImageLoader(ctx)
	}
	if imageBackend != nil {
		imgloadCtx, span := Tracer(ctx).Start(ctx, "configuring image store")
		c.imageLoader, err = imageBackend.Loader(imgloadCtx)
		if err != nil {
			err = fmt.Errorf("failed to get image loader: %w", err)
		}

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Check the wrapped cause (errors.As for *url.Error or gRPC status) for dial vs. RPC failure
  2. Retry — races between engine readiness and dial usually resolve
  3. Verify the engine container is running and its port/socket is reachable
  4. Confirm TLS/proxy configuration matches the engine's expectations

Example fix

// before
client, err := dagger.Connect(ctx) // engine still booting, dial fails
// after
var client *dagger.Client
for i := 0; i < 5; i++ {
    client, err = dagger.Connect(ctx)
    if err == nil || !strings.Contains(fmt.Sprint(err), "new client") {
        break
    }
    time.Sleep(2 * time.Second)
}
Defensive patterns

Strategy: retry

Validate before calling

// confirm the engine endpoint is listening before dialing
conn, err := net.DialTimeout("tcp", engineAddr, 5*time.Second)
if err != nil {
    return fmt.Errorf("engine not reachable at %s: %w", engineAddr, err)
}
conn.Close()

Type guard

func isNewClientErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "new client")
}

Try / catch

var client *dagger.Client
err := retry.Do(5, retry.Backoff(2*time.Second), func() error {
    var e error
    client, e = dagger.Connect(ctx)
    if e != nil && isNewClientErr(e) { return e } // retry dial
    return retry.Stop(e)
})

Prevention

When it happens

Trigger: Calling Connect/ConnectEngineToEngine when the buildkit gRPC dial to the started engine fails: engine not yet listening, wrong address, TLS misconfiguration, or the Info RPC times out.

Common situations: Slow engine startup exceeding dial timeout; engine container networking broken (host networking changes, port not exposed); proxy intercepting gRPC; clock skew breaking TLS.

Related errors


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