{"record":{"id":"8ff7bf351a283ed7","repo":"prometheus/node_exporter","slug":"failed-to-retrieve-btrfs-stats-from-procfs-w","errorCode":null,"errorMessage":"failed to retrieve Btrfs stats from procfs: %w","messagePattern":"failed to retrieve Btrfs stats from procfs: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/btrfs_linux.go","lineNumber":58,"sourceCode":"// NewBtrfsCollector returns a new Collector exposing Btrfs statistics.\nfunc NewBtrfsCollector(logger *slog.Logger) (Collector, error) {\n\tfs, err := btrfs.NewFS(*sysPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open sysfs: %w\", err)\n\t}\n\n\treturn &btrfsCollector{\n\t\tfs:     fs,\n\t\tlogger: logger,\n\t}, nil\n}\n\n// Update retrieves and exports Btrfs statistics.\n// It implements Collector.\nfunc (c *btrfsCollector) Update(ch chan<- prometheus.Metric) error {\n\tstats, err := c.fs.Stats()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to retrieve Btrfs stats from procfs: %w\", err)\n\t}\n\n\tioctlStatsMap, err := c.getIoctlStats()\n\tif err != nil {\n\t\tc.logger.Debug(\n\t\t\t\"Error querying btrfs device stats with ioctl\",\n\t\t\t\"err\", err)\n\t\tioctlStatsMap = make(map[string]*btrfsIoctlFsStats)\n\t}\n\n\tfor _, s := range stats {\n\t\t// match up procfs and ioctl info by filesystem UUID (without dashes)\n\t\tvar fsUUID = strings.ReplaceAll(s.UUID, \"-\", \"\")\n\t\tioctlStats := ioctlStatsMap[fsUUID]\n\t\tc.updateBtrfsStats(ch, s, ioctlStats)\n\t}\n\n\treturn nil","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/btrfs_linux.go#L40-L76","documentation":"btrfsCollector.Update wraps errors from c.fs.Stats() (the sysfs-based Btrfs statistics read) in \"failed to retrieve Btrfs stats from procfs\". The message is slightly misleading — it reads from sysfs via the btrfs fs package — but it signals that the statistics walk over /sys/fs/btrfs failed during a scrape. The whole btrfs scrape aborts for that cycle; ioctl-based device stats failures are only logged at debug level and do not cause this error.","triggerScenarios":"A scrape where /sys/fs/btrfs files could not be read (filesystem unmounted mid-scrape, permission revoked, sysfs read returning EIO), or a kernel change altering expected attribute paths.","commonSituations":"Unmounting or degraded btrfs arrays during scraping; container environments where sysfs visibility changed after startup; custom kernels lacking expected btrfs sysfs attributes.","solutions":["Confirm /sys/fs/btrfs still exists and is populated at scrape time","Check dmesg for btrfs errors and repair/remount affected filesystems","Verify permissions for the node_exporter user on the btrfs sysfs files","Ignore ioctl device-stat debug messages — they are non-fatal by design"],"exampleFix":"// before\n if err := ch-scrape; err != nil { panic(err) }\n// after\n if err := scrape(); err != nil {\n\tif strings.Contains(err.Error(), \"failed to retrieve Btrfs stats\") {\n\t\tlogger.Warn(\"btrfs stats unavailable this cycle\", \"err\", err)\n\t\treturn\n\t}\n\tpanic(err)\n }","handlingStrategy":"retry","validationCode":"if _, err := os.Stat(\"/sys/fs/btrfs\"); err != nil { /* skip scrape cycle */ }","typeGuard":null,"tryCatchPattern":"err := collector.Update(ch)\nif err != nil {\n\tlogger.Warn(\"btrfs stats scrape failed; retrying next interval\", \"err\", err)\n\treturn nil\n}","preventionTips":["Avoid unmounting btrfs filesystems during scrape windows","Monitor dmesg for btrfs sysfs read errors","Keep procfs dependency updated with kernel attribute changes","Alert only on persistent, not transient, scrape failures"],"tags":["linux","sysfs","scrape","btrfs"],"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"}