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

  1. Ensure /sys exists and is mounted (mount -t sysfs sysfs /sys)
  2. Correct the --path.sysfs flag to an existing sysfs root
  3. For tests, unpack fixtures via `make test` so collector/fixtures/sys exists
  4. 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

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


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)