prometheus/node_exporter · error

error obtaining NVMe class info

Error message

error obtaining NVMe class info: %w

What it means

The NVMe collector's Update calls c.fs.NVMeClass() to enumerate /sys/class/nvme devices and read their stats via the sysfs library. When the call fails for a reason other than os.ErrNotExist (the expected 'no NVMe devices' case, handled as ErrNoData), the error is wrapped in this message. It means sysfs is readable but the NVMe class data could not be listed or parsed.

Solutions

  1. Read the wrapped cause (%w) to determine permission vs parse vs I/O failure.
  2. Confirm exporter read access: 'ls -la /sys/class/nvme' as the exporter user.
  3. Retry/observe: transient errors during device hotplug usually clear on the next scrape; treat persistent ones as real failures.
  4. On parse failures with newer kernels, upgrade node_exporter/procfs sysfs package.
  5. On hosts without NVMe, expect ErrNoData debug logs instead of this error.

Example fix

// before: masked /sys/class in container causes listing errors
// after: mount host sysfs fully read-only
//   docker run -v /sys:/host/sys:ro node-exporter \
//     --path.sysfs=/host/sys --collector.nvme
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: precheck NVMe class directory accessibility
if ents, err := os.ReadDir(filepath.Join(*sysPath, "class/nvme")); err != nil {
    log.Printf("nvme class not readable: %v", err)
} else if len(ents) == 0 {
    log.Printf("no NVMe devices; collector will no-op")
}

Try / catch

// skip no-device case, wrap real errors
if errors.Is(err, os.ErrNotExist) {
    return ErrNoData
}
return fmt.Errorf("error obtaining NVMe class info: %w", err) // alert on persistence

Prevention

When it happens

Trigger: c.fs.NVMeClass() returns a non-ErrNotExist error: permission problems under /sys/class/nvme, partially removed NVMe devices changing state mid-read, or unexpected sysfs attribute content the sysfs library cannot parse.

Common situations: Hosts with hot-plugged/failing NVMe drives where device directories vanish between listing and reading; hardened containers that expose /sys but mask subpaths; kernel versions with attribute layouts newer than the bundled sysfs library supports.

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


AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07). Data as JSON: /api/errors/deee515ed4e238e0. Report an issue: GitHub.

Appendix: source

Thrown at collector/nvme_linux.go:94

func NewNVMeCollector(logger *slog.Logger) (Collector, error) {
	fs, err := sysfs.NewFS(*sysPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open sysfs: %w", err)
	}
	return &nvmeCollector{
		fs:     fs,
		logger: logger,
	}, nil
}

func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error {
	devices, err := c.fs.NVMeClass()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			c.logger.Debug("nvme statistics not found, skipping")
			return ErrNoData
		}
		return fmt.Errorf("error obtaining NVMe class info: %w", err)
	}

	for _, device := range devices {
		// Export device-level metrics
		ch <- prometheus.MustNewConstMetric(
			nvmeInfo,
			prometheus.GaugeValue,
			1.0,
			device.Name,
			device.FirmwareRevision,
			device.Model,
			device.Serial,
			device.State,
			device.ControllerID,
		)

		// Export namespace-level metrics
		for _, namespace := range device.Namespaces {

View on GitHub (pinned to 17ddd77c59)