slackhq/nebula · error

failed to create route.RouteMessage for change: %w

Error message

failed to create route.RouteMessage for change: %w

What it means

When adding a route returns EEXIST (route already present), addRoute retries by re-marshaling the same message as RTM_CHANGE. This error is returned if that second Marshal() fails, meaning the fallback route-update could not be serialized either.

Source

Thrown at overlay/tun_netbsd.go:493

			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 prefix/gateway values as for the initial marshal failure (valid netip.Prefix, matching families).
  2. Delete the stale existing route manually (route delete) and retry to confirm the message content is the problem.
  3. Log the prefix, gateway, and route message fields before Marshal to pinpoint the invalid data.
  4. Check the netroute library version for known NetBSD RTM_CHANGE serialization issues.
Defensive patterns

Strategy: validation

Validate before calling

// Same validation as RTM_ADD applies before the RTM_CHANGE fallback
if !prefix.IsValid() || len(gateways) == 0 || !gateways[0].Addr().IsValid() {
    return fmt.Errorf("cannot build RTM_CHANGE for invalid route %v", prefix)
}

Try / catch

if err := addRoute(prefix, gateways); err != nil {
    if strings.Contains(err.Error(), "route.RouteMessage for change") {
        // EEXIST fallback also failed to marshal — remove stale route and retry once
        _ = delRoute(prefix, gateways)
        return addRoute(prefix, gateways)
    }
    return err
}

Prevention

When it happens

Trigger: addRoute encountering unix.EEXIST on the initial RTM_ADD write, then route.Marshal() failing again for the RTM_CHANGE message due to malformed message fields.

Common situations: Same malformed-prefix causes as the RTM_ADD marshal failure; the route already existed from a previous run while the message fields are also subtly invalid.

Related errors


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