jaegertracing/jaeger · error

failed to convert aggregations to metrics: %w

Error message

failed to convert aggregations to metrics: %w

What it means

Translator.ToDomainMetricsFamily converts an Elasticsearch SearchResponse's aggregations into Jaeger's MetricFamily. If the internal toDomainMetrics step fails — e.g. aggregations are missing or malformed — the error is wrapped with this message so callers know the ES response could not be translated, distinguishing translation failures from query execution failures.

Source

Thrown at internal/storage/metricstore/elasticsearch/to_domain.go:34

// Translator converts raw Elasticsearch aggregation results into Jaeger's metrics domain model
// (metrics.MetricFamily). It uses a configurable function to extract values from buckets,
// ensuring flexibility across different metric types (e.g., latencies, call rates).
type Translator struct {
	bucketsToPointsFunc func(buckets []esclient.HistogramBucket) []*Pair
}

func NewTranslator(bucketsToPointsFunc func(buckets []esclient.HistogramBucket) []*Pair) Translator {
	return Translator{
		bucketsToPointsFunc: bucketsToPointsFunc,
	}
}

// ToDomainMetricsFamily converts Elasticsearch aggregations to Jaeger's MetricFamily.
func (t *Translator) ToDomainMetricsFamily(m MetricsQueryParams, result *esclient.SearchResponse) (*metrics.MetricFamily, error) {
	domainMetrics, err := t.toDomainMetrics(m, result)
	if err != nil {
		return nil, fmt.Errorf("failed to convert aggregations to metrics: %w", err)
	}

	if m.GroupByOperation {
		m.metricName = strings.Replace(m.metricName, "service", "service_operation", 1)
		m.metricDesc += " & operation"
	}

	return &metrics.MetricFamily{
		Name:    m.metricName,
		Type:    metrics.MetricType_GAUGE,
		Help:    m.metricDesc,
		Metrics: domainMetrics,
	}, nil
}

// toDomainMetrics converts Elasticsearch aggregations to Jaeger metrics.
func (t *Translator) toDomainMetrics(m MetricsQueryParams, result *esclient.SearchResponse) ([]*metrics.Metric, error) {
	labels := buildServiceLabels(m.ServiceNames)

View on GitHub (pinned to 806f444784)

Solutions

  1. Check the wrapped cause: usually '<aggName> aggregation not found' or 'failed to process bucket'.
  2. Verify the queried time range contains data and that ES metrics aggregation jobs are enabled.
  3. Confirm the response actually came from the Jaeger metrics indices, not an error page or different index.

Example fix

// verify response before translation
if result == nil || result.Aggregations == nil {
  return nil, fmt.Errorf("empty aggregations in search response")
}
fam, err := translator.ToDomainMetricsFamily(params, result)
Defensive patterns

Strategy: type-guard

Validate before calling

if result == nil || result.Aggregations == nil || len(result.Aggregations) == 0 {
  return fmt.Errorf("search response has no aggregations to convert")
}

Type guard

func hasAggregations(resp *esclient.SearchResponse, names ...string) bool {
  if resp == nil || resp.Aggregations == nil {
    return false
  }
  for _, n := range names {
    if _, ok := resp.Aggregations[n]; !ok {
      return false
    }
  }
  return true
}

Try / catch

fam, err := translator.ToDomainMetricsFamily(params, result)
if err != nil {
  log.Printf("translation failed: %v", err) // wrapped cause names the missing agg
  return emptyFamily
}

Prevention

When it happens

Trigger: Calling ToDomainMetricsFamily with a SearchResponse whose Aggregations do not contain the expected date_histogram (or terms, when GroupByOperation is set) aggregations, or whose buckets fail processing.

Common situations: Querying an ES cluster/index where the Jaeger metrics rollup jobs were never configured; response shape changed between ES versions; a proxy returning an error body that partially parses as a SearchResponse.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/16fa51bc5a05af75. Report an issue: GitHub.