prometheus/node_exporter · error

failed to open sysfs

Error message

failed to open sysfs: %w

What it means

On Linux, NewDiskstatsCollector opens the proc/sys filesystem with blockdevice.NewFS(*procPath, *sysPath) before building the collector. If that filesystem handle cannot be created (path missing, not a directory, or stat/permission errors), construction fails with "failed to open sysfs: %w".

Solutions

  1. Verify both paths exist and are directories: ls -d /proc /sys (or the values of --path.procfs / --path.sysfs).
  2. In containers, mount /proc and /sys into the container (e.g. -v /proc:/host/proc:ro -v /sys:/host/sys:ro with matching --path.* flags).
  3. Fix the incorrect --path.procfs / --path.sysfs flag values.
  4. Inspect the wrapped cause (%w) for permission errors and adjust the run user or mount options.
  5. Disable the diskstats collector if disk metrics are not required (--no-collector.diskstats).

Example fix

// before (container without mounts)
docker run prom/node-exporter --path.procfs=/host/proc
// after
 docker run -v /proc:/host/proc:ro -v /sys:/host/sys:ro prom/node-exporter --path.procfs=/host/proc --path.sysfs=/host/sys
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range []string{procPath, sysPath} {
    fi, err := os.Stat(p)
    if err != nil || !fi.IsDir() {
        // invalid --path.procfs/--path.sysfs; fix before starting
    }
}

Try / catch

if _, err := NewDiskstatsCollector(logger); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        log.Fatalf("proc/sys path invalid: %v", perr)
    }
    log.Fatalf("diskstats init failed: %v", err)
}

Prevention

When it happens

Trigger: node_exporter startup with the diskstats collector enabled when blockdevice.NewFS fails: --path.procfs or --path.sysfs points to a nonexistent/non-directory path, or permission errors occur validating either mount.

Common situations: Wrong --path.procfs/--path.sysfs values; containers missing /proc or /sys mounts; restricted environments where the exporter user cannot stat those paths; chroot/minimal images without the expected mounts.

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/69cd889a9698b352. Report an issue: GitHub.

Appendix: source

Thrown at collector/diskstats_linux.go:92

	descs                   []typedDesc
	filesystemInfoDesc      typedDesc
	deviceMapperInfoDesc    typedDesc
	ataDescs                map[string]typedDesc
	logger                  *slog.Logger
	getUdevDeviceProperties func(uint32, uint32) (udevInfo, error)
}

func init() {
	registerCollector("diskstats", defaultEnabled, NewDiskstatsCollector)
}

// NewDiskstatsCollector returns a new Collector exposing disk device stats.
// Docs from https://www.kernel.org/doc/Documentation/iostats.txt
func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) {
	var diskLabelNames = []string{"device"}
	fs, err := blockdevice.NewFS(*procPath, *sysPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open sysfs: %w", err)
	}

	deviceFilter, err := newDiskstatsDeviceFilter(logger)
	if err != nil {
		return nil, fmt.Errorf("failed to parse device filter flags: %w", err)
	}

	collector := diskstatsCollector{
		deviceFilter: deviceFilter,
		fs:           fs,
		infoDesc: typedDesc{
			desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, diskSubsystem, "info"),
				"Info of /sys/block/<block_device>.",
				[]string{"device", "major", "minor", "path", "wwn", "model", "serial", "revision", "rotational"},
				nil,
			), valueType: prometheus.GaugeValue,
		},
		descs: []typedDesc{

View on GitHub (pinned to 17ddd77c59)