{"record":{"id":"9b1f0e3b21bb84fa","repo":"prometheus/node_exporter","slug":"failed-to-scan-nvme-subsystems-w","errorCode":null,"errorMessage":"failed to scan NVMe subsystems: %w","messagePattern":"failed to scan NVMe subsystems: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/nvmesubsystem_linux.go","lineNumber":121,"sourceCode":"\tfs, err := sysfs.NewFS(*sysPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open sysfs: %w\", err)\n\t}\n\n\treturn &nvmeSubsystemCollector{\n\t\tfs:     fs,\n\t\tlogger: logger,\n\t}, nil\n}\n\nfunc (c *nvmeSubsystemCollector) Update(ch chan<- prometheus.Metric) error {\n\tsubsystems, err := c.fs.NVMeSubsystemClass()\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) {\n\t\t\tc.logger.Debug(\"Could not read NVMe subsystem info\", \"err\", err)\n\t\t\treturn ErrNoData\n\t\t}\n\t\treturn fmt.Errorf(\"failed to scan NVMe subsystems: %w\", err)\n\t}\n\n\tfor _, subsys := range subsystems {\n\t\tch <- prometheus.MustNewConstMetric(nvmesubsystemInfo, prometheus.GaugeValue, 1,\n\t\t\tsubsys.Name, subsys.NQN, subsys.Model, subsys.Serial, subsys.IOPolicy)\n\n\t\tfor _, ns := range subsys.Namespaces {\n\t\t\tch <- prometheus.MustNewConstMetric(nvmesubsystemNamespaceInfo, prometheus.GaugeValue, 1,\n\t\t\t\tsubsys.Name, ns)\n\t\t}\n\n\t\ttotal := float64(len(subsys.Controllers))\n\t\tvar live float64\n\t\tfor _, ctrl := range subsys.Controllers {\n\t\t\tstate := normalizeControllerState(ctrl.State)\n\t\t\tif state == \"live\" {\n\t\t\t\tlive++\n\t\t\t}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/nvmesubsystem_linux.go#L103-L139","documentation":"Update reads the NVMe subsystem class directory through c.fs.NVMeSubsystemClass(). If the scan fails with an error other than os.ErrNotExist/os.ErrPermission (which are downgraded to ErrNoData), it is wrapped as \"failed to scan NVMe subsystems\" and propagated as a scrape error. It represents an I/O or traversal problem while enumerating /sys/class/nvme-subsystem/.","triggerScenarios":"c.fs.NVMeSubsystemClass() returns an error that is neither ErrNotExist nor ErrPermission: e.g. the sysfs FS was constructed against a fixture/test root where reading class/nvme-subsystem fails with another I/O error, a readlink/readFile error while parsing subsystem attributes, or a corrupt/inaccessible entry.","commonSituations":"Scraping while sysfs entries disappear mid-scan (device hot-unplug); restricted environments where read errors are neither ENOENT nor EACCES (e.g. EIO from failing hardware); tests pointing the collector at a partially-populated fixture tree.","solutions":["Check the wrapped cause (%w) in the log to identify the underlying syscall error","Re-scrape; transient hotplug-related races typically resolve on the next scrape","Fix the failing sysfs hardware/medium if errors are persistent (EIO)","Verify the fixture/test root contains a well-formed class/nvme-subsystem directory","If the path legitimately may not exist, rely on ErrNoData handling already present for ErrNotExist"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(filepath.Join(*sysPath, \"class\", \"nvme-subsystem\")); err != nil || !fi.IsDir() { log.Println(\"nvme-subsystem class dir unavailable; ErrNoData expected\") }","typeGuard":"func nvmeClassReadable(sysPath string) bool {\n    f, err := os.Open(filepath.Join(sysPath, \"class\", \"nvme-subsystem\"))\n    if err != nil { return false }\n    f.Close()\n    return true\n}","tryCatchPattern":"if err := c.Update(ch); err != nil {\n    var nd collector.ErrNoData\n    if errors.As(err, &nd) { return nil }\n    if strings.Contains(err.Error(), \"failed to scan NVMe subsystems\") {\n        logger.Warn(\"transient NVMe scan failure, will retry next scrape\", \"err\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["Handle ErrNoData separately from hard failures in scrape handlers","Monitor for persistent wrapped errors (EIO) as a hardware-health signal","Re-check sysfs stability during hotplug windows before diagnosing","Keep procfs/sysfs dependencies updated so parsing matches kernel layout"],"tags":["linux","sysfs","nvme","scrape"],"backgroundTag":"file-read-failed","analyzedSha":"17ddd77c59ba27e1508e9f7894b1e55b44d6aed3","analyzedAt":"2026-09-07T17:54:06.211Z","contentChangedAt":"2026-09-07T17:54:06.211Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}