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 successfully marshaled the RTM_ADD message but the write to the AF_ROUTE routing socket failed. This error wraps that write failure, meaning the kernel did not accept the route-add request via the routing socket.

Source

Thrown at overlay/tun_netbsd.go:498

	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. Inspect the wrapped errno via errors.Is to distinguish EINVAL (bad message) from other I/O errors.
  2. Verify the target interface is up and exists at the time addRoutes runs.
  3. Validate prefix/gateway fields (family, validity) before building the RouteMessage.
  4. Retry activation if the failure was transient (e.g. EINTR) or serialize route operations to avoid races.
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the interface the route points at is up before writing the route message
iface, err := net.InterfaceByName(devName)
if err != nil {
    return fmt.Errorf("interface %s not present; cannot add route: %w", devName, err)
}
if iface.Flags&net.FlagUp == 0 {
    return fmt.Errorf("interface %s is down", devName)
}

Try / catch

var err error
for i := 0; i < 3; i++ {
    if err = addRoute(prefix, gateways); err == nil {
        break
    }
    var errno syscall.Errno
    if errors.As(err, &errno) && (errno == unix.EINTR || errno == unix.EAGAIN) {
        time.Sleep(time.Duration(1<<i) * 100 * time.Millisecond)
        continue
    }
    break
}
if err != nil { return err }

Prevention

When it happens

Trigger: unix.Write(sock, data) failing after a successful Marshal — e.g. the socket was closed, the kernel rejected the message (EINVAL/ESRCH), or a transient I/O error occurred on the raw socket.

Common situations: Kernel rejecting a route message with invalid fields not caught by Marshal; interface disappearing between socket creation and write; very large route batches racing with route-table changes.

Related errors


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