slackhq/nebula · error

failed to create route.RouteMessage for change: %w

Error message

failed to create route.RouteMessage for change: %w

What it means

After an RTM_ADD write fails with EEXIST, addRoute retries with an RTM_CHANGE message and re-marshals the RouteMessage. If Marshal() fails on this second attempt, the error is wrapped as 'failed to create route.RouteMessage for change'. As with the add case, it indicates the in-memory route message cannot be serialized for the kernel.

Source

Thrown at overlay/tun_openbsd.go:472

			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
}

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{

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Validate the route prefix/gateway families in tun.routes config so the RouteMessage fields are always well-formed.
  2. Update golang.org/x/net to a version compatible with your Go toolchain, since netroute internals can shift.
  3. Inspect any local modifications to addRoute; RTM_CHANGE messages must not include attributes the kernel rejects (e.g. gateway type mismatch).
  4. Log the failing route prefix and gateway at debug level to identify the offending config entry.
Defensive patterns

Strategy: validation

Validate before calling

// same family/validity check as the add path
for _, r := range routes {
	if !r.Gateway.IsValid() {
		return fmt.Errorf("invalid gateway for %s", r.Route)
	}
}

Try / catch

if err := addRoute(prefix, gateways); err != nil {
	if strings.Contains(err.Error(), "for change") {
		// non-retryable serialization failure; log route details and abort
	}
}

Prevention

When it happens

Trigger: The first unix.Write returned unix.EEXIST (route already present), route.Type was set to unix.RTM_CHANGE, and the re-Marshal of the same route data returned an error — i.e. the same invalid field combination as error 460, encountered on the change path.

Common situations: Re-adding an existing route (EEXIST path) on OpenBSD with a malformed gateway/prefix from config; library version drift in x/net/route making the message invalid for both add and change.

Related errors


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