slackhq/nebula · error

failed to write route.RouteMessage to socket: %w

Error message

failed to write route.RouteMessage to socket: %w

What it means

addRoute built and marshaled a RouteMessage successfully, but the write to the AF_ROUTE raw socket failed (and the failure was not EEXIST). The error is wrapped as 'failed to write route.RouteMessage to socket'. This means the kernel routing socket refused the route addition.

Source

Thrown at overlay/tun_openbsd.go:477

	data, err := route.Marshal()
	if err != nil {
		return fmt.Errorf("failed to create route.RouteMessage: %w", err)
	}

	_, err = unix.Write(sock, data[:])
	if err != nil {
		if errors.Is(err, unix.EEXIST) {
			// Try to do a change
			route.Type = unix.RTM_CHANGE
			data, err = route.Marshal()
			if err != nil {
				return fmt.Errorf("failed to create route.RouteMessage for change: %w", err)
			}
			_, err = unix.Write(sock, data[:])
			return err
		}
		return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
	}

	return nil
}

func delRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
	sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
	if err != nil {
		return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
	}
	defer unix.Close(sock)

	route := netroute.RouteMessage{
		Version: unix.RTM_VERSION,
		Type:    unix.RTM_DELETE,
		Seq:     1,
	}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Run the process as root or with the required privileges — OpenBSD routing sockets need effective privileges.
  2. Check that the gateway address is itself reachable via another route; RTM_ADD with an unreachable gateway fails.
  3. Retry or ignore EEXIST-like races; if another tool manages overlapping routes, remove the conflicting tun.routes entries.
  4. Capture the wrapped errno (%w) from the error chain to distinguish EPERM vs ESRCH vs EINVAL and fix accordingly.
Defensive patterns

Strategy: try-catch

Validate before calling

// check privileges early
if unix.Geteuid() != 0 {
	return errors.New("route management requires root privileges on OpenBSD")
}

Try / catch

if err := addRoute(prefix, gws); err != nil {
	var syscallErr unix.Errno
	if errors.As(err, &syscallErr) {
		switch syscallErr {
		case unix.EPERM: /* rerun as root */
		case unix.EEXIST: /* already present */
		default: log.Error("route add failed", "errno", syscallErr)
		}
	}
}

Prevention

When it happens

Trigger: unix.Write(sock, data) on the AF_ROUTE socket returns a non-EEXIST error during addRoute (called from addIp or addRoutes) — e.g. EPERM for missing privileges, EINVAL/ESRCH for a bad route, or ENOBUFS under kernel pressure.

Common situations: Running nebula without root/CAP_NET_ADMIN on OpenBSD so the routing socket rejects RTM_ADD; a gateway that doesn't exist in the routing table (ESRCH); route conflicts with another daemon (routing daemons like ospfd/relayd).

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/5648f99cac158312. Report an issue: GitHub.