{"record":{"id":"c93c711f5e55811d","repo":"prometheus/node_exporter","slug":"unknown-metric-type","errorCode":null,"errorMessage":"unknown metric type","messagePattern":"unknown metric type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/textfile.go","lineNumber":145,"sourceCode":"\t\t\t\tquantiles, values...,\n\t\t\t)\n\t\tcase dto.MetricType_HISTOGRAM:\n\t\t\tbuckets := map[float64]uint64{}\n\t\t\tfor _, b := range metric.Histogram.Bucket {\n\t\t\t\tbuckets[b.GetUpperBound()] = b.GetCumulativeCount()\n\t\t\t}\n\t\t\tch <- prometheus.MustNewConstHistogram(\n\t\t\t\tprometheus.NewDesc(\n\t\t\t\t\t*metricFamily.Name,\n\t\t\t\t\tmetricFamily.GetHelp(),\n\t\t\t\t\tnames, nil,\n\t\t\t\t),\n\t\t\t\tmetric.Histogram.GetSampleCount(),\n\t\t\t\tmetric.Histogram.GetSampleSum(),\n\t\t\t\tbuckets, values...,\n\t\t\t)\n\t\tdefault:\n\t\t\tpanic(\"unknown metric type\")\n\t\t}\n\t\tif metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {\n\t\t\tch <- prometheus.MustNewConstMetric(\n\t\t\t\tprometheus.NewDesc(\n\t\t\t\t\t*metricFamily.Name,\n\t\t\t\t\tmetricFamily.GetHelp(),\n\t\t\t\t\tnames, nil,\n\t\t\t\t),\n\t\t\t\tvalType, val, values...,\n\t\t\t)\n\t\t}\n\t}\n}\n\nfunc (c *textFileCollector) exportMTimes(mtimes map[string]time.Time, ch chan<- prometheus.Metric) {\n\tif len(mtimes) == 0 {\n\t\treturn\n\t}","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/prometheus/node_exporter/blob/17ddd77c59ba27e1508e9f7894b1e55b44d6aed3/collector/textfile.go#L127-L163","documentation":"convertMetricFamily in collector/textfile.go switches on the protobuf metric type of each MetricFamily parsed from a .prom textfile and panics with \"unknown metric type\" when the family's type is none of COUNTER, GAUGE, UNTYPED, SUMMARY, or HISTOGRAM. Since the textfile parser produces those five types plus METRIC_TYPE_UNKNOWN-equivalents, this panic fires on families whose type field is unset, invalid, or comes from a newer client_golang dto with an unrecognized type value.","triggerScenarios":"A .prom file in the textfile collector directory contains a # TYPE line that expvar/promtext parsing maps to an unset or unknown dto.MetricType (e.g. an empty/garbage TYPE line), or the parsed dto.MetricFamily carries a type value not covered by the switch (such as MetricType_GAUGE_HISTOGRAM from a newer protobuf schema).","commonSituations":"Hand-written or tool-generated .prom files with malformed # TYPE comments; stale textfile files written by an older exporter version; a client_model/client_golang upgrade introducing new MetricType enum values while node_exporter's textfile switch has not been extended.","solutions":["Find the offending .prom file in the textfile collector directory (--collector.textfile.directory, default /var/lib/node_exporter/textfile_collector) and fix or remove its malformed/missing # TYPE line","Validate the file with promtool check metrics before writing it; have writers emit only counter/gauge/untyped/summary/histogram types","If it comes from a new client_model MetricType enum value, add a case (or skip-with-warning) for it in convertMetricFamily instead of panicking","As a workaround, replace the metric with an equivalent untyped one (# TYPE name untyped) that the switch handles"],"exampleFix":"// before\ndefault:\n\tpanic(\"unknown metric type\")\n// after\ndefault:\n\tlogger.Warn(\"Ignoring unsupported metric type in textfile\", \"type\", metricType, \"metric\", *metricFamily.Name)\n\tcontinue","handlingStrategy":"validation","validationCode":"// validate a .prom file before dropping it into the textfile directory\nf, err := os.Open(path)\nif err != nil {\n\treturn err\n}\ndefer f.Close()\np, err := expfmt.NewTextParser(0).TextToMetricFamilies(f)\nif err != nil {\n\treturn err\n}\nfor name, mf := range p {\n\tswitch mf.GetType() {\n\tcase dto.MetricType_COUNTER, dto.MetricType_GAUGE, dto.MetricType_UNTYPED,\n\t\tdto.MetricType_SUMMARY, dto.MetricType_HISTOGRAM:\n\tdefault:\n\t\treturn fmt.Errorf(\"metric %s has unsupported type %s\", name, mf.GetType())\n\t}\n}","typeGuard":"func isSupportedMetricType(t *dto.MetricType) bool {\n\tswitch *t {\n\tcase dto.MetricType_COUNTER, dto.MetricType_GAUGE, dto.MetricType_UNTYPED,\n\t\tdto.MetricType_SUMMARY, dto.MetricType_HISTOGRAM:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"// The panic happens inside the collector's scrape; if embedding convertMetricFamily in a fork, recover per family:\nfunc safeConvert(mf *dto.MetricFamily, ch chan<- prometheus.Metric, logger *slog.Logger) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlogger.Warn(\"skipping bad textfile metric family\", \"family\", mf.GetName(), \"panic\", r)\n\t\t}\n\t}()\n\tconvertMetricFamily(mf, ch, logger)\n}","preventionTips":["Only write .prom files that pass promtool check metrics into the textfile directory","Write files atomically (tmp file + rename) so a partially written TYPE line is never parsed","Keep client_golang/client_model versions consistent between the metric writer and node_exporter","Emit untyped for metrics whose kind is uncertain instead of omitting or inventing a TYPE line"],"tags":["go","panic","textfile","prometheus","protobuf"],"backgroundTag":"invalid-enum-value","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"}