prometheus/node_exporter · error
devstat_getdevs failed
Error message
devstat_getdevs failed
What it means
In the FreeBSD devstat collector (devstat_freebsd.go), Update calls the cgo helper C._get_stats(c.devinfo, &stats), which wraps devstat_getdevs. A return of -1 means the kernel device-statistics query failed, so the collector cannot read any disk metrics and returns this error for the scrape.
Solutions
- Grant the exporter's user permission to read /dev/devstat (devfs.rules or group membership)
- Restart node_exporter to refresh its cached devinfo after device changes/hot-plug
- Confirm devstat is available on the host (kern.devstat sysctl exists) and the process is not jailed without device access
- Disable the diskstats collector on hosts where devstat is not usable
Defensive patterns
Strategy: try-catch
Try / catch
if err := c.Update(ch); err != nil {
if strings.Contains(err.Error(), "devstat_getdevs failed") {
c.logger.Warn("devstat query failed; refreshing state may help", "err", err)
}
return err
} Prevention
- Ensure /dev/devstat is readable by the exporter user (devfs.rules, group membership)
- Restart the exporter after hot-plug device changes so cached devinfo stays valid
- Confirm the host is not jailed without devstat visibility
- Verify kern.devstat sysctl exists during provisioning
When it happens
Trigger: C._get_stats(c.devinfo, &stats) == -1 in devstatCollector.Update — devstat_getdevs failed, most commonly because /dev/devstat cannot be opened by the exporter process, or devinfo is stale after a device-list change.
Common situations: node_exporter lacking read permission on /dev/devstat; running inside a FreeBSD jail without devstat access; devstat state invalidated after hot-plug device changes.
Related errors
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/4248e9a26c2079dd.
Report an issue: GitHub.
Appendix: source
Thrown at collector/devstat_freebsd.go:92
[]string{"device"}, nil,
), prometheus.CounterValue},
blocks: typedDesc{prometheus.NewDesc(
prometheus.BuildFQName(namespace, devstatSubsystem, "blocks_transferred_total"),
"The total number of blocks transferred.",
[]string{"device"}, nil,
), prometheus.CounterValue},
logger: logger,
}, nil
}
func (c *devstatCollector) Update(ch chan<- prometheus.Metric) error {
c.mu.Lock()
defer c.mu.Unlock()
var stats *C.Stats
n := C._get_stats(c.devinfo, &stats)
if n == -1 {
return errors.New("devstat_getdevs failed")
}
base := unsafe.Pointer(stats)
for i := C.int(0); i < n; i++ {
offset := i * C.int(C.sizeof_Stats)
stat := (*C.Stats)(unsafe.Pointer(uintptr(base) + uintptr(offset)))
device := fmt.Sprintf("%s%d", C.GoString(&stat.device[0]), stat.unit)
ch <- c.bytes.mustNewConstMetric(float64(stat.bytes.read), device, "read")
ch <- c.bytes.mustNewConstMetric(float64(stat.bytes.write), device, "write")
ch <- c.transfers.mustNewConstMetric(float64(stat.transfers.other), device, "other")
ch <- c.transfers.mustNewConstMetric(float64(stat.transfers.read), device, "read")
ch <- c.transfers.mustNewConstMetric(float64(stat.transfers.write), device, "write")
ch <- c.duration.mustNewConstMetric(float64(stat.duration.other), device, "other")
ch <- c.duration.mustNewConstMetric(float64(stat.duration.read), device, "read")
ch <- c.duration.mustNewConstMetric(float64(stat.duration.write), device, "write")
ch <- c.busyTime.mustNewConstMetric(float64(stat.busyTime), device)
ch <- c.blocks.mustNewConstMetric(float64(stat.blocks), device)View on GitHub (pinned to 17ddd77c59)