prometheus/node_exporter · error
error obtaining PCI device info
Error message
error obtaining PCI device info: %w
What it means
Update enumerates PCI devices with c.fs.PciDevices(). ErrNotExist is downgraded to a debug log + ErrNoData, but any other error is wrapped as "error obtaining PCI device info" and fails the scrape. This signals an unexpected failure while reading PCI device attributes from sysfs, distinct from simply having no PCI info available.
Solutions
- Inspect the wrapped cause (%w) in the scrape error to identify the failing file/syscall
- Re-scrape after fixing underlying I/O problems; check dmesg for PCI hardware errors
- Ensure the process has read access to /sys/bus/pci/devices (avoid over-aggressive LSM/masked paths)
- Fix or regenerate test fixtures if running against a truncated sysfs fixture root
- If PCI info is genuinely absent, verify why ErrNotExist path isn't taken (path exists but is unreadable)
Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(filepath.Join(*sysPath, "bus", "pci", "devices")); err != nil || !fi.IsDir() { log.Println("pci devices dir unreadable") } Type guard
func pciDevicesReadable(sysPath string) bool {
f, err := os.Open(filepath.Join(sysPath, "bus", "pci", "devices"))
if err != nil { return false }
f.Close()
return true
} Try / catch
if err := c.Update(ch); err != nil {
if strings.Contains(err.Error(), "error obtaining PCI device info") {
logger.Warn("PCI scrape failed; skipping this cycle", "err", err)
return nil // next scrape may succeed
}
return err
} Prevention
- Do not mask /sys/bus/pci in container security policies if PCI metrics are needed
- Treat repeated EIO-based failures as hardware alerts (check dmesg/lspci)
- Keep the sysfs/procfs library current to track kernel sysfs layout changes
- Regenerate test fixtures when sysfs layout in tests drifts
When it happens
Trigger: c.fs.PciDevices() returns a non-ErrNotExist error: permission/IO failures reading /sys/bus/pci/devices entries, readlink or attribute-read errors (e.g. EIO, EACCES variants not matching the check), malformed device directories in a test fixture root.
Common situations: Failing PCI hardware producing EIO during attribute reads; containers where most of sysfs is masked and reads return unusual errors; partially-populated test fixtures; kernel changes altering expected sysfs layout handled upstream in procfs/sysfs.
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
- failed to retrieve bcache stats
- failed to retrieve bcachefs stats
- failed to retrieve Btrfs stats from procfs
- failed to scan DM-multipath devices
- couldn't get NUMA meminfo
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/477cc391e6be5a12.
Report an issue: GitHub.
Appendix: source
Thrown at collector/pcidevice_linux.go:206
prometheus.BuildFQName(namespace, pcideviceSubsystem, "info"),
"Non-numeric data from /sys/bus/pci/devices/<location>, value is always 1.",
labelNames,
nil,
),
valueType: prometheus.GaugeValue,
}
return c, nil
}
func (c *pcideviceCollector) Update(ch chan<- prometheus.Metric) error {
devices, err := c.fs.PciDevices()
if err != nil {
if errors.Is(err, os.ErrNotExist) {
c.logger.Debug("PCI device not found, skipping")
return ErrNoData
}
return fmt.Errorf("error obtaining PCI device info: %w", err)
}
for _, device := range devices {
// The device location is represented in separated format.
values := device.Location.Strings()
if device.ParentLocation != nil {
values = append(values, device.ParentLocation.Strings()...)
} else {
values = append(values, []string{"*", "*", "*", "*"}...)
}
// Add basic device information
classID := fmt.Sprintf("0x%06x", device.Class)
vendorID := fmt.Sprintf("0x%04x", device.Vendor)
deviceID := fmt.Sprintf("0x%04x", device.Device)
subsysVendorID := fmt.Sprintf("0x%04x", device.SubsystemVendor)
subsysDeviceID := fmt.Sprintf("0x%04x", device.SubsystemDevice)
View on GitHub (pinned to 17ddd77c59)