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
- Validate the route prefix/gateway families in tun.routes config so the RouteMessage fields are always well-formed.
- Update golang.org/x/net to a version compatible with your Go toolchain, since netroute internals can shift.
- Inspect any local modifications to addRoute; RTM_CHANGE messages must not include attributes the kernel rejects (e.g. gateway type mismatch).
- 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
- Don't rely on the EEXIST->RTM_CHANGE fallback for malformed routes; fix the input instead.
- Log prefix/gateway when route application fails to identify bad config entries.
- Test route add/change/delete on your OpenBSD release after dependency upgrades.
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
- failed to create route.RouteMessage: %w
- failed to write route.RouteMessage to socket: %w
- failed to create route.RouteMessage: %w
- failed to set route for vpn network %v: %w
- ErrInvalidLocalIP
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/da9c7b015e26a2c3.
Report an issue: GitHub.