prometheus/node_exporter · error
failed to open sysfs
Error message
failed to open sysfs: %w
What it means
NewTapestatsCollector constructs its collector by opening a sysfs filesystem handle via sysfs.NewFS(*sysPath) (default /sys). If that path cannot be opened/read as a filesystem, the collector cannot be created and construction fails with this wrapped error. This is a startup-time failure, not a scrape-time one.
Solutions
- Check the --path.sysfs value points at a mounted sysfs directory (default /sys)
- Mount sysfs if missing: on hosts it is normally there; in containers pass --path.sysfs=/host/sys with -v /sys:/host/sys:ro
- Test access manually: ls /sys/class/scsi_tape as the user node_exporter runs as
- If tapestats is not needed, disable it with --collector.tapestats to avoid constructing the collector
Example fix
// before: container without sysfs docker run prom/node-exporter --collector.tapestats // after docker run -v /sys:/host/sys:ro prom/node-exporter --path.sysfs=/host/sys
Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(*sysPath); err != nil || !fi.IsDir() {
// fix --path.sysfs before enabling tapestats
} Try / catch
coll, err := NewTapestatsCollector(logger)
if err != nil {
logger.Warn("tapestats disabled", "err", err)
coll = nil
} Prevention
- Keep the default --path.sysfs=/sys unless you have a specific reason
- In containers, bind-mount /sys read-only and set --path.sysfs accordingly
- Only enable --collector.tapestats on hosts with SCSI tape devices
- Check filesystem mounts before deploying to minimal images
When it happens
Trigger: The --path.sysfs flag points at a nonexistent or unreadable directory, or sysfs.NewFS cannot stat/access the given root path at collector construction time.
Common situations: Typo in --path.sysfs when testing; running node_exporter in a minimal container where /sys is not mounted; chroot/jail environments without sysfs mounted; permission restrictions from seccomp/AppArmor blocking /sys access.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- failed to open sysfs
- failed to open sysfs
- failed to open sysfs
- failed to open sysfs
- failed to open sysfs
AI-assisted analysis of prometheus/node_exporter@17ddd77c59 (2026-09-07).
Data as JSON: /api/errors/6effc8bd6276cdb4.
Report an issue: GitHub.
Appendix: source
Thrown at collector/tapestats_linux.go:60
writesCompletedTotal *prometheus.Desc
writeTimeSeconds *prometheus.Desc
residualTotal *prometheus.Desc
fs sysfs.FS
logger *slog.Logger
}
func init() {
registerCollector("tapestats", defaultEnabled, NewTapestatsCollector)
}
// NewTapestatsCollector returns a new Collector exposing tape device stats.
// Docs from https://www.kernel.org/doc/html/latest/scsi/st.html#sysfs-and-statistics-for-tape-devices
func NewTapestatsCollector(logger *slog.Logger) (Collector, error) {
var tapeLabelNames = []string{"device"}
fs, err := sysfs.NewFS(*sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %w", err)
}
tapeSubsystem := "tape"
return &tapestatsCollector{
ignoredDevicesPattern: regexp.MustCompile(*ignoredTapeDevices),
ioNow: prometheus.NewDesc(
prometheus.BuildFQName(namespace, tapeSubsystem, "io_now"),
"The number of I/Os currently outstanding to this device.",
tapeLabelNames, nil,
),
ioTimeSeconds: prometheus.NewDesc(
prometheus.BuildFQName(namespace, tapeSubsystem, "io_time_seconds_total"),
"The amount of time spent waiting for all I/O to complete (including read and write). This includes tape movement commands such as seeking between file or set marks and implicit tape movement such as when rewind on close tape devices are used.",
tapeLabelNames, nil,
),
othersCompletedTotal: prometheus.NewDesc(View on GitHub (pinned to 17ddd77c59)