prometheus/node_exporter · error
couldn't get sysctl
Error message
couldn't get sysctl: %w
What it means
The FreeBSD netisr collector reads each configured sysctl OID (via the gosysctl-style m.Value() call) to export netisr queue/processing metrics. Any failure reading a sysctl value is wrapped as 'couldn't get sysctl' and aborts the Update, dropping all node_netisr_* metrics for that scrape.
Solutions
- Run `sysctl net.isr` (or the specific OID) manually on the host to confirm it exists and is readable.
- If inside a jail, run node_exporter on the host or grant the jail access to the needed sysctls.
- Check the FreeBSD version matches what the node_exporter release supports; upgrade the exporter for newer/renamed OIDs.
- Read the wrapped inner error to see which sysctl name failed.
- Temporarily disable the collector (--collector.disable-defaults, enable others) if netisr metrics are not required.
Defensive patterns
Strategy: validation
Validate before calling
// preflight on FreeBSD: verify sysctl OIDs are readable
for _, name := range []string{"net.isr.num_threads", "net.isr.drop"} {
if _, err := sysctl.Sysctl(name); err != nil {
return fmt.Errorf("sysctl %s unreadable: %w", name, err)
}
} Try / catch
err := collector.Update(ch)
if err != nil && strings.Contains(err.Error(), "couldn't get sysctl") {
logger.Warn("netisr sysctl unavailable; skipping netisr scrape", "cause", err)
return nil
} Prevention
- Verify `sysctl net.isr` output on the target host before enabling the collector
- Do not run inside jails without sysctl access; run on the host instead
- Match node_exporter version to FreeBSD release (OID names change across versions)
- Track the wrapped sysctl name in logs to spot renamed OIDs after upgrades
When it happens
Trigger: m.Value() fails for one of c.sysctls: the OID does not exist on this kernel (netisr disabled or renamed), the sysctl name string is malformed, or reading is denied by permissions/jail restrictions.
Common situations: Running inside a FreeBSD jail where netisr sysctls are hidden; FreeBSD version differences that renamed or removed net.*.netisr OIDs; building with a stale sysctl list after a FreeBSD upgrade; typos in collector-maintained sysctl names.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Data Size mismatch
- sysctl(vm.stats.vm.v_page_size) failed
- couldn't get memory
- invalid TCP states data: expected
- could not retrieve CPU times
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/4bb5797a7c691a15.
Report an issue: GitHub.
Appendix: source
Thrown at collector/netisr_freebsd.go:92
valueType: prometheus.GaugeValue,
},
{
name: "maxthreads",
description: "netisr maximum thread count",
mib: "net.isr.maxthreads",
dataType: bsdSysctlTypeUint32,
valueType: prometheus.GaugeValue,
},
},
logger: logger,
}, nil
}
func (c *netisrCollector) Update(ch chan<- prometheus.Metric) error {
for _, m := range c.sysctls {
v, err := m.Value()
if err != nil {
return fmt.Errorf("couldn't get sysctl: %w", err)
}
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(namespace, netisrCollectorSubsystem, m.name),
m.description,
nil, nil,
), m.valueType, v)
}
return nil
}
View on GitHub (pinned to 17ddd77c59)