slackhq/nebula · error

failed to create route.RouteMessage for change: %w

Error message

failed to create route.RouteMessage for change: %w

What it means

In addRoute (overlay/tun_freebsd.go:654), when adding a route via an AF_ROUTE socket fails with unix.EEXIST, the code retries with an RTM_CHANGE route.RouteMessage. This error is thrown if route.Marshal() fails while building that change message, meaning the route message could not be serialized for the kernel routing socket.

Source

Thrown at overlay/tun_freebsd.go:654

			unix.RTAX_DST:     &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
			unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
			unix.RTAX_GATEWAY: gateway,
		}
	}

	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, gateway netroute.Addr) 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{

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Verify the gateway and prefix use the same address family (both IPv4 or both IPv6) in the tunneled_routes / route configuration.
  2. Check the wrapped err (%w) for the specific Marshal failure (e.g. address family mismatch, message too large) and correct the offending route entry.
  3. Update Go/x/sys and netroute dependencies, since Marshal behavior changed across versions.
  4. Simplify unusual route entries (very long flag combinations) that could exceed the RTM message size limit.

Example fix

// before
routes:
  - prefix: 10.0.0.0/8
    gateway: fd00::1   # IPv6 gateway for IPv4 route
// after
routes:
  - prefix: 10.0.0.0/8
    gateway: 10.0.0.1  # matching IPv4 gateway
Defensive patterns

Strategy: validation

Validate before calling

func validRoutePair(prefix netip.Prefix, gw netroute.Addr) bool {
	return (prefix.Addr().Is4() && gw.Is4()) || (prefix.Addr().Is6() && gw.Is6())
}

Type guard

func isSameFamily(prefix netip.Prefix, gw netroute.Addr) bool {
	return prefix.Addr().BitLen() == gw.BitLen()
}

Try / catch

if err := addRoute(prefix, gw); err != nil {
	var merr *fmt.WrapError // inspect wrapped Marshal cause
	log.Printf("route change marshal failed for %v via %v: %v", prefix, gw, err)
}

Prevention

When it happens

Trigger: Calling addRoute with a prefix/gateway combination whose marshaled RouteMessage exceeds the buffer capacity (RS_MAX size limits), or an invalid address family (e.g. a gateway netip.Addr that doesn't match the prefix's family) causing netroute.RouteMessage.Marshal to fail.

Common situations: Configured routes where the gateway address family mismatches the destination prefix (IPv4 route with IPv6 gateway or vice versa); corrupted runtime route state after a reload; extremely unusual route options making the message exceed kernel buffer size.

Related errors


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