cilium/cilium · error
unable to replace the mtu %d for the route %s: %s
Error message
unable to replace the mtu %d for the route %s: %s
What it means
While iterating IPv4 routes in route-MTU mode, the plugin rewrites each route's MTU to Cilium's RouteMTU via netlink.RouteReplace. This error reports the target MTU, the route string, and the kernel's error message when the replacement fails. It means the pod's routing table could not be updated, which can break Cilium's egress/ingress datapath assumptions for the chained mode.
Source
Thrown at plugins/cilium-cni/chaining/generic-veth/generic-veth.go:150
break
}
if !linkFound {
return errors.New("no link found inside container")
}
if pluginCtx.NetConf.EnableRouteMTU || pluginCtx.CiliumConf.EnableRouteMTUForCNIChaining {
routes, err := safenetlink.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
err = fmt.Errorf("unable to list the IPv4 routes: %w", err)
return err
}
for _, rt := range routes {
if rt.MTU != int(pluginCtx.CiliumConf.RouteMTU) {
rt.MTU = int(pluginCtx.CiliumConf.RouteMTU)
err = netlink.RouteReplace(&rt)
if err != nil {
err = fmt.Errorf("unable to replace the mtu %d for the route %s: %s", rt.MTU, rt.String(), err.Error())
return err
}
}
}
routes, err = safenetlink.RouteList(nil, netlink.FAMILY_V6)
if err != nil {
err = fmt.Errorf("unable to list the IPv6 routes: %w", err)
return err
}
for _, rt := range routes {
if rt.MTU != int(pluginCtx.CiliumConf.RouteMTU) {
rt.MTU = int(pluginCtx.CiliumConf.RouteMTU)
err = netlink.RouteReplace(&rt)
if err != nil {
err = fmt.Errorf("unable to replace the mtu %d for the route %s: %s", rt.MTU, rt.String(), err.Error())
return err
}View on GitHub (pinned to ac7b90affa)
Solutions
- Read the %s kernel error in the message: EPERM → restore CAP_NET_ADMIN; ESRCH/ENETUNREACH → the route vanished (retry the pod).
- Verify 'route-mtu' in the Cilium ConfigMap matches the underlying CNI's expectations (e.g. aws-cni's 9001).
- Ensure only one component manages route MTU: disable enableRouteMTU if the primary CNI already sets MTU.
- Retry pod creation; transient races usually resolve on retry.
Example fix
// before (Cilium ConfigMap) enable-route-mtu: "true" route-mtu: "0" // after enable-route-mtu: "true" route-mtu: "9001"
Defensive patterns
Strategy: validation
Validate before calling
// Validate before enabling route MTU patching
if ciliumConf.RouteMTU < 68 || ciliumConf.RouteMTU > 65535 {
return fmt.Errorf("invalid route-mtu %d configured", ciliumConf.RouteMTU)
} Try / catch
err = netlink.RouteReplace(&rt)
if err != nil {
switch {
case errors.Is(err, os.ErrPermission):
// missing CAP_NET_ADMIN in netns
case errors.Is(err, syscall.ESRCH):
// route removed concurrently — retry
}
return fmt.Errorf("unable to replace the mtu %d for the route %s: %s", rt.MTU, rt.String(), err.Error())
} Prevention
- Guarantee the CNI plugin retains CAP_NET_ADMIN in the container netns (don't strip caps in runtime config).
- Have exactly one MTU manager: either the primary CNI or Cilium's enableRouteMTU, not both.
- Set route-mtu to the value matching the underlying CNI (e.g. 9001 on AWS).
When it happens
Trigger: netlink.RouteReplace(&rt) fails for a specific IPv4 route inside the container netns: e.g. EPERM (missing CAP_NET_ADMIN in the netns), the route was concurrently deleted, invalid MTU value, or the route is unreachable/locked by another manager.
Common situations: Container runtime dropping CAP_NET_ADMIN from the CNI plugin's netns context; conflicting MTU managers (both Cilium and a secondary CNI mutating MTU); RouteMTU set to 0 or an invalid value in the Cilium ConfigMap; route disappearing mid-loop due to concurrent networking changes.
Related errors
- unable to list the IPv4 routes: %w
- unable to list the IPv6 routes: %w
- unable to determine name of veth pair on the host side
- unable to determine MAC address of veth pair on the host sid
- unable to determine MAC address of veth pair on the containe
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/c014b55a116eb600.
Report an issue: GitHub.