prometheus/node_exporter · error
failed to open sysfs
Error message
failed to open sysfs: %w
What it means
NewPcideviceCollector builds a collector exposing PCI device stats from sysfs. It calls sysfs.NewFS(*sysPath) using the --path.sysfs flag and wraps any failure in "failed to open sysfs". sysfs.NewFS validates that the path is an accessible filesystem, so construction fails when the sysfs root is missing or unusable.
Solutions
- Ensure /sys exists and is mounted (mount -t sysfs sysfs /sys)
- Correct the --path.sysfs flag to an existing sysfs root
- For tests, unpack fixtures via `make test` so collector/fixtures/sys exists
- Bind-mount host /sys into the container read-only when running in Docker
Example fix
// before mount -t proc proc /proc # sysfs never mounted // after mount -t sysfs sysfs /sys # then start node_exporter --collector.pcidevice
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(*sysPath); err != nil { return fmt.Errorf("sysfs path %q missing: %w", *sysPath, err) } Type guard
func sysfsReady(path string) bool { st, err := os.Stat(path); return err == nil && st.IsDir() } Try / catch
c, err := collector.NewPcideviceCollector(logger)
if err != nil {
if strings.Contains(err.Error(), "failed to open sysfs") {
logger.Warn("PCI collector disabled: sysfs unavailable", "err", err)
return nil
}
return err
} Prevention
- Mount sysfs in containers/chroots before enabling PCI collection
- Validate --path.sysfs at deployment time with a pre-start check
- Unpack sysfs fixtures before running unit tests (make test)
- Use read-only bind mounts of /sys in Docker (--read-only friendly)
When it happens
Trigger: NewPcideviceCollector returns this when sysfs.NewFS(*sysPath) errors: --path.sysfs does not exist, /sys is not mounted (containers, chroots), or the sysfs root passed by the caller (e.g. TestPCICollectorWithNameResolution fixtures) is invalid.
Common situations: Wrong --path.sysfs flag value; container images without sysfs mounted; test fixtures not unpacked (make test unpacks sys.ttar); running on non-Linux where sysfs does not exist.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- failed to open sysfs
- failed to open sysfs
- failed to open sysfs
- failed to open sysfs
- error obtaining PCI device info
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/9af3b508940e0d83.
Report an issue: GitHub.
Appendix: source
Thrown at collector/pcidevice_linux.go:165
logger *slog.Logger
pciVendors map[string]string
pciDevices map[string]map[string]string
pciSubsystems map[string]map[string]string
pciClasses map[string]string
pciSubclasses map[string]string
pciProgIfs map[string]string
pciNames bool
}
func init() {
registerCollector("pcidevice", defaultDisabled, NewPcideviceCollector)
}
// NewPcideviceCollector returns a new Collector exposing PCI devices stats.
func NewPcideviceCollector(logger *slog.Logger) (Collector, error) {
fs, err := sysfs.NewFS(*sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %w", err)
}
// Initialize PCI ID maps
c := &pcideviceCollector{
fs: fs,
logger: logger,
pciNames: *pciNames,
}
// Build label names based on whether name resolution is enabled
labelNames := append(pcideviceLabelNames,
[]string{"parent_segment", "parent_bus", "parent_device", "parent_function",
"class_id", "vendor_id", "device_id", "subsystem_vendor_id", "subsystem_device_id", "revision"}...)
if c.pciNames {
c.loadPCIIds()
// Add name labels when name resolution is enabled
labelNames = append(labelNames, "vendor_name", "device_name", "subsystem_vendor_name", "subsystem_device_name", "class_name")View on GitHub (pinned to 17ddd77c59)