netbirdio/netbird · error

startup: %w

Error message

startup: %w

What it means

Returned by Client.Start when the ConnectClient run loop exits with an error before the engine finishes starting (the 'startup' channel path). This is the engine's permanent/startup backoff error: interface creation failure, management stream failure, or any engine subsystem that aborts during initial bring-up. It is distinct from the context-deadline path: here the run loop itself failed.

Source

Thrown at client/embed/embed.go:293

		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()

	if c.connect == nil {
		return ErrClientNotStarted
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Unwrap the error to find which subsystem failed: 'new wg interface' points at TUN/netstack/privileges, stream errors at management.
  2. If NoUserspace=true, ensure the process has the required privileges (root/CAP_NET_ADMIN) and kernel WireGuard support; otherwise keep userspace mode.
  3. Check management connectivity and protocol compatibility, then retry Start with a new client.
  4. Enable debug logging (Options.LogLevel "debug") to get the engine-side reason, which is often logged rather than returned.
Defensive patterns

Strategy: try-catch

Try / catch

if err := client.Start(ctx); err != nil {
    if strings.Contains(err.Error(), "startup:") {
        log.Debug-level engine logs carry the real cause; unwrap and classify before retrying
    }
}

Prevention

When it happens

Trigger: Client.Start where newWgIface or engine start fails: no TUN/netstack available in the environment, MTU rejected again at engine level, management connection drops mid-start, or privileged operations fail when NoUserspace=true without root.

Common situations: Running with NoUserspace=true inside a container without NET_ADMIN/root; a host where the netstack/TUN setup fails (seccomp blocking the syscall); management connection reset during initial sync; version skew between embedded client and management protocol.

Related errors


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