{"record":{"id":"03dbd8c3190d67b9","repo":"prometheus/node_exporter","slug":"failed-to-stat-q-w","errorCode":null,"errorMessage":"failed to stat %q: %w","messagePattern":"failed to stat %q: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/textfile.go","lineNumber":310,"sourceCode":"\t\treturn nil, nil, fmt.Errorf(\"failed to open textfile data file %q: %w\", path, err)\n\t}\n\tdefer f.Close()\n\n\tparser := expfmt.NewTextParser(model.UTF8Validation)\n\tfamilies, err := parser.TextToMetricFamilies(f)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to parse textfile data from %q: %w\", path, err)\n\t}\n\n\tif hasTimestamps(families) {\n\t\treturn nil, nil, fmt.Errorf(\"textfile %q contains unsupported client-side timestamps, skipping entire file\", path)\n\t}\n\n\t// Only stat the file once it has been parsed and validated, so that\n\t// a failure does not appear fresh.\n\tstat, err := f.Stat()\n\tif err != nil {\n\t\treturn nil, families, fmt.Errorf(\"failed to stat %q: %w\", path, err)\n\t}\n\n\tt := stat.ModTime()\n\treturn &t, families, nil\n}\n\n// hasTimestamps returns true when metrics contain unsupported timestamps.\nfunc hasTimestamps(parsedFamilies map[string]*dto.MetricFamily) bool {\n\tfor _, mf := range parsedFamilies {\n\t\tfor _, m := range mf.Metric {\n\t\t\tif m.TimestampMs != nil {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/textfile.go#L292-L328","documentation":"After a file parses successfully, processFile calls f.Stat() to obtain the modification time used as the mtime label for staleness detection. If Stat fails, the metrics cannot be safely timestamped, so the error is wrapped as this message (note it returns the parsed families alongside the error).","triggerScenarios":"f.Stat() fails on an already-open file — typically when the file was deleted/replaced on disk between open and stat (the fd is still valid but the stat call errors in unusual filesystem conditions), or I/O errors on exotic filesystems.","commonSituations":"Writers aggressively replacing/removing files in the textfile directory during scrape; NFS or FUSE mounts where stat on open handles can fail; permission changes mid-scrape.","solutions":["Make writers use atomic rename so files in the directory are never deleted while being scraped","Point --collector.textfile.directory at a local filesystem (tmpfs/ext4), not NFS/FUSE","Re-run the scrape — this is usually transient; check whether node_exporter.textfile.scrape_error stays elevated","Check filesystem health (dmesg, mount options) if it persists on local disks"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if _, err := os.Stat(filepath.Join(dir, name)); err != nil {\n    // file vanished; skip this scrape cycle\n}","typeGuard":null,"tryCatchPattern":"if err := coll.Update(ch); err != nil {\n    if strings.Contains(err.Error(), \"failed to stat\") {\n        // transient — retry on next scrape interval\n        log.Debug(\"textfile stat failed transiently\", \"err\", err)\n    }\n}","preventionTips":["Use atomic rename-based writes so files never vanish mid-scrape","Keep the textfile directory on a local filesystem, not NFS/FUSE","Alert on persistent node_exporter textfile scrape errors, not single occurrences","Periodically clean stale files from the textfile directory"],"tags":["textfile","filesystem","stat","linux"],"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"}