prometheus/node_exporter · error

failed to open sysfs

Error message

failed to open sysfs: %w

What it means

NewDMMultipathCollector wraps a failure from blockdevice.NewFS(*procPath, *sysPath) as "failed to open sysfs". The block device FS constructor validates both the procfs and sysfs roots; this error indicates one of them could not be used, preventing the dm-multipath collector from being created.

Solutions

  1. Verify both --path.procfs (default /proc) and --path.sysfs (default /sys) point to mounted, readable directories
  2. Mount procfs and sysfs into the container: -v /proc:/proc:ro -v /sys:/sys:ro
  3. Correct any typo or override of the path flags
  4. Check that the paths are directories, not regular files or symlinks to nothing

Example fix

// before
node_exporter --path.sysfs=/sysfs-typo
// after
node_exporter --path.sysfs=/sys
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

c, err := collector.NewDMMultipathCollector(logger)
if err != nil {
    return fmt.Errorf("dm-multipath collector disabled: %w", err)
}

Prevention

When it happens

Trigger: blockdevice.NewFS fails because --path.procfs or --path.sysfs does not exist, is unreadable, or is not a directory. Called from NewDMMultipathCollector during collector registration and from the dm-multipath tests.

Common situations: Containerized node_exporter without /sys or /proc mounted; typo'd --path.sysfs/--path.procfs flags; running on non-Linux where the expected mounts are absent despite the build-tag-gated collector being enabled.

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

Appendix: source

Thrown at collector/dmmultipath_linux.go:88

	)
	dmmultipathPathState = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "dmmultipath", "path_state"),
		"Reports the underlying device state for a multipath path, as read from /sys/block/<dev>/device/state.",
		[]string{"device", "path", "state"}, nil,
	)
)

type dmMultipathCollector struct {
	fs     blockdevice.FS
	logger *slog.Logger
}

// NewDMMultipathCollector returns a new Collector exposing Device Mapper
// multipath device metrics from /sys/block/dm-*.
func NewDMMultipathCollector(logger *slog.Logger) (Collector, error) {
	fs, err := blockdevice.NewFS(*procPath, *sysPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open sysfs: %w", err)
	}

	return &dmMultipathCollector{
		fs:     fs,
		logger: logger,
	}, nil
}

func (c *dmMultipathCollector) Update(ch chan<- prometheus.Metric) error {
	devices, err := c.fs.DMMultipathDevices()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) {
			c.logger.Debug("Could not read DM-multipath devices", "err", err)
			return ErrNoData
		}
		return fmt.Errorf("failed to scan DM-multipath devices: %w", err)
	}

View on GitHub (pinned to 17ddd77c59)