netbirdio/netbird · error

stop error after context done. Stop error: %w. Context done:

Error message

stop error after context done. Stop error: %w. Context done: %w

What it means

Returned by Client.Start when the caller's startCtx is cancelled or its deadline expires while the engine is still coming up, and additionally ConnectClient.Stop reports an error during the forced teardown. The message wraps both the stop error and the context error, so the primary cause is almost always 'startup did not finish before the deadline' with a secondary teardown failure.

Source

Thrown at client/embed/embed.go:289

	// TODO: make after-startup backoff err available
	run := make(chan struct{})
	clientErr := make(chan error, 1)
	go func() {
		if err := client.Run(run, ""); err != nil {
			clientErr <- err
		}
	}()

	select {
	case <-startCtx.Done():
		// ConnectClient.Stop now cancels its own run context and waits for the
		// run loop to tear the engine down, so this cancel() is no longer
		// required to break the deadlock and could be removed. It is kept as a
		// defensive belt-and-suspenders: cancelling the parent context first
		// guarantees the run loop is unblocked even if Stop's contract regresses.
		cancel()
		if stopErr := client.Stop(); stopErr != nil {
			return fmt.Errorf("stop error after context done. Stop error: %w. Context done: %w", stopErr, startCtx.Err())
		}
		return startCtx.Err()
	case err := <-clientErr:
		return fmt.Errorf("startup: %w", err)
	case <-run:
	}

	c.connect = client
	c.cancel = cancel

	return nil
}

// Stop gracefully stops the client.
// Pass a context with a deadline to limit the time spent waiting for the engine to stop.
func (c *Client) Stop(ctx context.Context) error {
	c.mu.Lock()
	defer c.mu.Unlock()

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Increase or remove the deadline on the context passed to Start; engine startup legitimately takes seconds.
  2. Fix the underlying slowness: verify management reachability/latency, DNS resolution, and peer connectivity to the management port.
  3. Retry Start with a fresh client instance and backoff for transient slowness.
  4. If the stop error itself is the mystery, capture it from the wrapped message and investigate teardown separately.

Example fix

// before
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
err := client.Start(ctx)

// after
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
err := client.Start(ctx)
Defensive patterns

Strategy: retry

Try / catch

if err := client.Start(startCtx); err != nil {
    if errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "context done") {
        // widen the deadline and retry with a fresh client
    }
}

Prevention

When it happens

Trigger: Client.Start with a short-deadline context on a slow network; management server slow to sync the network map; engine start blocked on firewall/DNS/interface setup. The stop error can be any engine teardown error occurring while unwinding.

Common situations: First connection on constrained or far-away networks (handshake + sync exceeds a few seconds); strict deadlines copied from unit tests into production; management under load. Users often misread this as a stop bug when the actionable half is the deadline.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/66c8478cad2d8c43. Report an issue: GitHub.