slackhq/nebula · error

failed to create route.RouteMessage: %w

Error message

failed to create route.RouteMessage: %w

What it means

In overlay/tun_openbsd.go addRoute, the route.RouteMessage built for adding a route to the OpenBSD routing socket fails route.Marshal(). This means the message could not be serialized into the binary wire format the kernel routing socket expects. It is a programming/configuration error in the route parameters (address family, addresses, flags), not a transient network problem.

Source

Thrown at overlay/tun_openbsd.go:462

			unix.RTAX_DST:     &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
			unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},
			unix.RTAX_GATEWAY: &netroute.Inet4Addr{IP: gw.Addr().As4()},
		}
	} else {
		gw, err := selectGateway(prefix, gateways)
		if err != nil {
			return err
		}
		route.Addrs = []netroute.Addr{
			unix.RTAX_DST:     &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
			unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
			unix.RTAX_GATEWAY: &netroute.Inet6Addr{IP: gw.Addr().As16()},
		}
	}

	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

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Check the tun.routes / tun.unsafe_routes config: ensure each route's prefix and gateway address family is consistent (IPv4 prefix with IPv4 gateway, IPv6 with IPv6).
  2. Confirm the gateway netip.Prefix has a valid Addr (not the zero value) before As16() is called; fix the calling config.
  3. Check the OpenBSD/Go version compatibility of golang.org/x/net/netroute (internal API changed across versions) and update dependencies to a known-good combo.
  4. If you patched addRoute, verify all RTAX_* attributes you set are valid for RTM_ADD and that Inet4Addr/Inet6Addr types match the message's Addrs bitmap.

Example fix

// before
// IPv4 route reaching the IPv6 gateway branch
unix.RTAX_GATEWAY: &netroute.Inet6Addr{IP: gw.Addr().As16()},
// after
// branch by family
if gw.Addr().Is4() {
	attrs[unix.RTAX_GATEWAY] = &netroute.Inet4Addr{IP: gw.Addr().As4()}
} else {
	attrs[unix.RTAX_GATEWAY] = &netroute.Inet6Addr{IP: gw.Addr().As16()}
}
Defensive patterns

Strategy: validation

Validate before calling

for _, r := range routes {
	if !r.Gateway.IsValid() || r.Gateway.Addr().Is4() != r.Route.Addr().Is4() {
		return fmt.Errorf("route %s gateway %s family mismatch", r.Route, r.Gateway)
	}
}

Try / catch

if err := overlay.AddRoutes(routes); err != nil {
	var marshalErr error
	if errors.Unwrap(err) != nil && strings.Contains(err.Error(), "Marshal") {
		marshalErr = err // invalid route message; fix config, not retryable
	}
}

Prevention

When it happens

Trigger: addRoute (called by addIp or addRoutes) constructs a netroute.RouteMessage with an invalid combination of fields (e.g. unsupported address family, malformed netip.Addr conversion via As16, wrong RTAX index) so route.Marshal() returns an error.

Common situations: Running nebula on OpenBSD with a VPN network prefix or gateway whose family doesn't match the branch that builds the message; porting changes to the route-message construction; unusual tunnel::routes config entries that produce IPv4 routes through the IPv6 branch or vice versa.

Related errors


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