prometheus/node_exporter · error
couldn't connect rtnetlink
Error message
couldn't connect rtnetlink: %w
What it means
The network_route collector's Update dials the rtnetlink netlink socket (rtnetlink.Dial) to enumerate links and routes. If the netlink socket cannot be created or bound, Update returns this wrapped error and the route metrics are not scraped.
Solutions
- Verify the kernel supports netlink (it does on all standard Linux) and that the exporter process can create netlink sockets (test with `ss -f netlink` or a small Go probe).
- Review seccomp/AppArmor/SELinux profiles for the exporter and allow AF_NETLINK socket creation.
- Run the exporter outside restrictive sandboxes or relax the runtime's syscall filter.
- If the collector isn't needed, start node_exporter without the network_route collector (--collector.network-route disabled / blacklist flag).
Example fix
// before
conn, err := rtnetlink.Dial(nil)
if err != nil {
return fmt.Errorf("couldn't connect rtnetlink: %w", err)
}
// after (surface the underlying cause context)
conn, err := rtnetlink.Dial(nil)
if err != nil {
return fmt.Errorf("couldn't connect rtnetlink (netlink socket blocked? check seccomp/permissions): %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
import "golang.org/x/sys/unix"
// Probe netlink socket capability before enabling the collector:
fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, unix.NETLINK_ROUTE)
if err != nil {
// rtnetlink unavailable in this sandbox; disable network-route collector
} else {
unix.Close(fd)
} Type guard
null
Try / catch
// Fall back gracefully when netlink is blocked
conn, err := rtnetlink.Dial(nil)
if err != nil {
logger.Warn("rtnetlink unavailable; skipping network_route metrics", "err", err)
return nil
} Prevention
- Verify seccomp/AppArmor/SELinux profiles permit AF_NETLINK socket creation for the exporter.
- Test node_exporter inside the actual sandbox (gVisor, Kata, hardened runtimes) before rollout.
- Disable --collector.network-route where netlink is intentionally unavailable.
- Run the exporter with an account allowed to open netlink sockets.
When it happens
Trigger: rtnetlink.Dial(nil) fails when netlink sockets are unavailable: no NETLINK_ROUTE support, seccomp/apparmor/SELinux blocking socket(AF_NETLINK), or a container runtime without netlink in the sandbox.
Common situations: Hardened containers (seccomp profiles blocking netlink); restricted service users without CAP_NET_ADMIN-ish socket permissions; unusual sandboxes/gVisor environments lacking rtnetlink.
Related errors
- could not get net class info
- couldn't get links
- couldn't get routes
- failed to initialize ethtool library
- could not get link modes
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/326b64a783afe200.
Report an issue: GitHub.
Appendix: source
Thrown at collector/network_route_linux.go:64
)
routesDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "routes"),
"network routes by interface", []string{"device"}, nil,
)
return &networkRouteCollector{
routeInfoDesc: routeInfoDesc,
routesDesc: routesDesc,
logger: logger,
}, nil
}
func (n networkRouteCollector) Update(ch chan<- prometheus.Metric) error {
deviceRoutes := make(map[string]int)
conn, err := rtnetlink.Dial(nil)
if err != nil {
return fmt.Errorf("couldn't connect rtnetlink: %w", err)
}
defer conn.Close()
links, err := conn.Link.List()
if err != nil {
return fmt.Errorf("couldn't get links: %w", err)
}
routes, err := conn.Route.List()
if err != nil {
return fmt.Errorf("couldn't get routes: %w", err)
}
for _, route := range routes {
if route.Type != unix.RTA_DST {
continue
}
if len(route.Attributes.Multipath) != 0 {View on GitHub (pinned to 17ddd77c59)