netbirdio/netbird · error

invalid MTU: %w

Error message

invalid MTU: %w

What it means

Returned by embed.New when Options.MTU is non-nil and fails iface.ValidateMTU, which enforces the range 576..8192 bytes (MinMTU/MaxMTU in client/iface/iface.go). The MTU is validated eagerly at construction so an out-of-range value never reaches the tunnel interface. The wrapped error states whether the value is below the minimum or above the maximum.

Source

Thrown at client/embed/embed.go:157

	if credentialsProvided == 0 {
		return fmt.Errorf("one of SetupKey, JWTToken, or PrivateKey must be provided")
	}
	if credentialsProvided > 1 {
		return fmt.Errorf("only one of SetupKey, JWTToken, or PrivateKey can be specified")
	}

	return nil
}

// New creates a new netbird embedded client.
func New(opts Options) (*Client, error) {
	if err := opts.validateCredentials(); err != nil {
		return nil, err
	}

	if opts.MTU != nil {
		if err := iface.ValidateMTU(*opts.MTU); err != nil {
			return nil, fmt.Errorf("invalid MTU: %w", err)
		}
	}

	if opts.LogOutput != nil {
		logrus.SetOutput(opts.LogOutput)
	}

	if opts.LogLevel != "" {
		level, err := logrus.ParseLevel(opts.LogLevel)
		if err != nil {
			return nil, fmt.Errorf("parse log level: %w", err)
		}
		logrus.SetLevel(level)
	}

	if !opts.NoUserspace {
		if err := os.Setenv(netstack.EnvUseNetstackMode, "true"); err != nil {
			return nil, fmt.Errorf("setenv: %w", err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Set Options.MTU to a value in 576..8192; 1280 is the default (iface.DefaultMTU) and 1400 is typical when carrying QUIC.
  2. Leave Options.MTU nil to keep the existing config MTU or fall back to the default instead of passing 0.
  3. Call iface.ValidateMTU(mtu) yourself before embed.New to produce the error at your own validation boundary with your own message.

Example fix

// before
mtu := uint16(0) // means "unset" in the caller's config
client, err := embed.New(embed.Options{MTU: &mtu})

// after
var mtu *uint16
if cfgMTU > 0 {
    m := uint16(cfgMTU)
    mtu = &m
}
client, err := embed.New(embed.Options{MTU: mtu})
Defensive patterns

Strategy: validation

Validate before calling

import "github.com/netbirdio/netbird/client/iface"

if opts.MTU != nil {
    if err := iface.ValidateMTU(*opts.MTU); err != nil {
        return fmt.Errorf("reject options before embed.New: %w", err)
    }
}

Prevention

When it happens

Trigger: Calling embed.New with MTU set to a pointer holding a value < 576 (e.g. 512 or 0 copied from a default uint16) or > 8192 (e.g. 9000 'jumbo frame' values or a value read from a config that used a different unit).

Common situations: Copying an MTU tuned for a physical NIC (1500/9000) into the overlay config; treating 0 as 'unset' while the API uses a nil pointer for 'unset'; reading MTU from a JSON/YAML config as int and truncating/overflowing into uint16.

Related errors


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