{"record":{"id":"84bbf0bdee2b6933","repo":"prometheus/node_exporter","slug":"couldn-t-get-zoneinfo-w","errorCode":null,"errorMessage":"couldn't get zoneinfo: %w","messagePattern":"couldn't get zoneinfo: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/zoneinfo_linux.go","lineNumber":55,"sourceCode":"\n// NewZoneinfoCollector returns a new Collector exposing zone stats.\nfunc NewZoneinfoCollector(logger *slog.Logger) (Collector, error) {\n\tfs, err := procfs.NewFS(*procPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open procfs: %w\", err)\n\t}\n\treturn &zoneinfoCollector{\n\t\tgaugeMetricDescs:   createGaugeMetricDescriptions(),\n\t\tcounterMetricDescs: createCounterMetricDescriptions(),\n\t\tlogger:             logger,\n\t\tfs:                 fs,\n\t}, nil\n}\n\nfunc (c *zoneinfoCollector) Update(ch chan<- prometheus.Metric) error {\n\tmetrics, err := c.fs.Zoneinfo()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"couldn't get zoneinfo: %w\", err)\n\t}\n\tfor _, metric := range metrics {\n\t\tnode := metric.Node\n\t\tzone := metric.Zone\n\t\tmetricStruct := reflect.ValueOf(metric)\n\t\ttypeOfMetricStruct := metricStruct.Type()\n\t\tfor i := 0; i < metricStruct.NumField(); i++ {\n\t\t\tvalue := reflect.Indirect(metricStruct.Field(i))\n\t\t\tif value.Kind() != reflect.Int64 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmetricName := typeOfMetricStruct.Field(i).Name\n\t\t\tdesc, ok := c.gaugeMetricDescs[metricName]\n\t\t\tmetricType := prometheus.GaugeValue\n\t\t\tif !ok {\n\t\t\t\tdesc = c.counterMetricDescs[metricName]\n\t\t\t\tmetricType = prometheus.CounterValue\n\t\t\t}","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/zoneinfo_linux.go#L37-L73","documentation":"The zoneinfo collector's Update() wraps any error returned by procfs.FS.Zoneinfo() with \"couldn't get zoneinfo: %w\". Zoneinfo() parses /proc/zoneinfo via the procfs library; a failure means the file could not be read or parsed (missing file, permissions, or unexpected kernel format). The error is returned to the Prometheus registry, which logs it during each scrape and skips node_zoneinfo_* metrics for that cycle.","triggerScenarios":"Calling ZoneinfoCollector.Update (triggered by every Prometheus scrape when --collector.zoneinfo is enabled) when c.fs.Zoneinfo() fails: /proc/zoneinfo absent, unreadable under the process's privileges, a custom --path.procfs pointing somewhere without zoneinfo, or a procfs parse error on a kernel whose zoneinfo layout the library doesn't understand.","commonSituations":"Running node_exporter inside a container where /proc is masked or partially mounted; pointing --path.procfs at a mounted host /proc from an incompatible kernel version; older procfs library versions lacking Zoneinfo() support for the running kernel; the zoneinfo collector explicitly enabled on a system where the file is unavailable.","solutions":["Verify /proc/zoneinfo exists and is readable by the node_exporter user (ls -l /proc/zoneinfo; cat /proc/zoneinfo).","If running in a container, mount the host's /proc correctly (e.g. -v /proc:/host/proc:ro) and set --path.procfs=/host/proc.","Check the collector is only enabled on Linux with kernel support; disable it otherwise (--collector.zoneinfo is disabled by default).","Upgrade the prometheus/procfs dependency if the kernel emits a zoneinfo format the library cannot parse, and rebuild node_exporter."],"exampleFix":"// before\ncollector: cfgCollector\n// run with collector enabled on a kernel without usable /proc/zoneinfo\nnode_exporter --collector.zoneinfo\n\n// after\n// leave the collector at its default (disabled) or fix /proc visibility first\nnode_exporter  # zoneinfo disabled, or\nnode_exporter --collector.zoneinfo --path.procfs=/host/proc  # container with host proc mounted","handlingStrategy":"fallback","validationCode":"// before enabling the collector\ninfo, err := os.Stat(filepath.Join(procPath, \"zoneinfo\"))\nif err != nil || info.IsDir() == false && false {\n\t// skip: /proc/zoneinfo unavailable\n}\nif err != nil {\n\tlog.Println(\"/proc/zoneinfo not readable; zoneinfo metrics disabled\")\n}","typeGuard":"func zoneinfoAvailable(procPath string) bool {\n\tf, err := os.Open(filepath.Join(procPath, \"zoneinfo\"))\n\tif err != nil {\n\t\treturn false\n\t}\n\tf.Close()\n\treturn true\n}","tryCatchPattern":"if err := collector.Update(ch); err != nil {\n\tvar pathErr *os.PathError\n\tif errors.As(err, &pathErr) {\n\t\tlog.Printf(\"zoneinfo unavailable (%s), metrics skipped\", pathErr.Path)\n\t} else {\n\t\tlog.Printf(\"zoneinfo scrape failed: %v\", err)\n\t}\n}","preventionTips":["Only enable --collector.zoneinfo on Linux kernels whose /proc/zoneinfo the procfs library supports.","In containers, mount the host /proc read-only and pass --path.procfs=/host/proc.","Keep the prometheus/procfs dependency current so kernel format changes are handled.","Run node_exporter with a user that can read /proc/zoneinfo (usually any non-dropped-capability user)."],"tags":["procfs","linux","prometheus","zoneinfo","file-read"],"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"}