thanos-io/thanos · error
invalid temporality for metric
Error message
invalid temporality for metric %q
What it means
FromMetrics iterates all OTLP metrics and checks isValidAggregationTemporality per metric. Only cumulative (and delta for certain types) temporality is supported for Prometheus remote-write translation; a metric with an unsupported temporality (e.g. unspecified) adds this error and skips the metric.
Solutions
- Configure the exporter/SDK to emit cumulative temporality (default) or the temporality the receiver accepts
- Fix producers that construct metrics without setting AggregationTemporality explicitly
- Use the collector deltatocumulative or aggregate processors to convert delta to cumulative before forwarding
- Check which metric names are listed in the error set and align their instrument temporality settings
Example fix
# before: exporter configured for unsupported temporality otlp: temporality_preference: delta # after otlp: temporality_preference: cumulative
Defensive patterns
Strategy: validation
Validate before calling
for _, m := range ms {
if !isValidAggregationTemporality(m) {
log.Warnf("metric %q has unsupported temporality %v", m.Name(), m.AggregationTemporality())
}
} Type guard
func supportedTemporality(m pmetric.Metric) bool {
switch m.Type() {
case pmetric.MetricTypeHistogram:
return m.Histogram().AggregationTemporality() == pmetric.AggregationTemporalityCumulative
case pmetric.MetricTypeExponentialHistogram:
return m.ExponentialHistogram().AggregationTemporality() == pmetric.AggregationTemporalityCumulative
case pmetric.MetricTypeSum:
return m.Sum().AggregationTemporality() == pmetric.AggregationTemporalityCumulative
default:
return true
}
} Try / catch
_, err := translator.FromMetrics(ctx, md, settings)
if err != nil {
var annots annotations.Annotations
if errors.As(err, &annots) {
for _, a := range annots {
if strings.Contains(a.Error(), "invalid temporality") {
log.Warnf("skipped metric: %v", a)
continue
}
}
}
} Prevention
- Set temporality_preference: cumulative on all OTLP exporters
- Reject or convert delta metrics at the collector boundary
- Validate metric payloads in a staging pipeline before production
When it happens
Trigger: Sending OTLP metrics whose AggregationTemporality is TemporalityUnspecified or a temporality unsupported for that metric type (e.g. delta gauge-like sums depending on feature gates) through the OTLP->PRW converter.
Common situations: Producers/SConstructors that forget to set temporality on histogram/sum instruments; gateways stripping temporality; mixing cumulative and delta streams; OTLP exporters configured for delta when the receiver only accepts cumulative.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- unsupported metric type
- could not calculate compaction progress
- could not calculate retention progress
- could not calculate downsampling progress
- empty name for metric family
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/c0d77609b2174c2d.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/receive/otlptranslator/metrics_to_prw.go:86
scopeMetricsSlice := resourceMetrics.ScopeMetrics()
// keep track of the most recent timestamp in the ResourceMetrics for
// use with the "target" info metric
var mostRecentTimestamp pcommon.Timestamp
for j := 0; j < scopeMetricsSlice.Len(); j++ {
metricSlice := scopeMetricsSlice.At(j).Metrics()
// TODO: decide if instrumentation library information should be exported as labels
for k := 0; k < metricSlice.Len(); k++ {
if err := c.everyN.checkContext(ctx); err != nil {
errs.Add(err)
return
}
metric := metricSlice.At(k)
mostRecentTimestamp = max(mostRecentTimestamp, mostRecentTimestampInMetric(metric))
if !isValidAggregationTemporality(metric) {
errs.Add(fmt.Errorf("invalid temporality for metric %q", metric.Name()))
continue
}
promName := BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes, settings.AllowUTF8)
c.metadata = append(c.metadata, prompb.MetricMetadata{
Type: otelMetricTypeToPromMetricType(metric),
MetricFamilyName: promName,
Help: metric.Description(),
Unit: metric.Unit(),
})
// handle individual metrics based on type
//exhaustive:enforce
switch metric.Type() {
case pmetric.MetricTypeGauge:
dataPoints := metric.Gauge().DataPoints()
if dataPoints.Len() == 0 {
errs.Add(fmt.Errorf("empty data points. %s is dropped", metric.Name()))View on GitHub (pinned to 35b8b99117)