jaegertracing/jaeger · error

failed to stop the adaptive sampling aggregator

Error message

failed to stop the adaptive sampling aggregator : %w

What it means

This error wraps failures from aggregator.Close() when the adaptive sampling trace processor shuts down. The aggregator must flush pending sampling statistics and release the distributed lock; if graceful shutdown fails, the close lifecycle hook wraps the underlying error so the collector reports which component failed to stop.

Solutions

  1. Read the wrapped inner error to identify which shutdown step failed (lock release vs worker shutdown)
  2. Ensure the distributed-lock backend is reachable during shutdown so the aggregator can release its lock
  3. Give the collector a sufficient shutdown timeout so background sampling workers can exit
  4. If it recurs, check the sampling store health; repeated Close failures usually indicate an unhealthy backend

Example fix

# before: too-short shutdown kills the aggregator mid-flush
# after: allow time for graceful stop in collector config
service:
  telemetry: ...
# run collector with a longer shutdown grace period, e.g.
# ensure dist-lock backend is up: docker compose up etcd
Defensive patterns

Strategy: try-catch

Validate before calling

if tp.aggregator != nil {
    // check backend health before shutdown to anticipate Close failures
    if err := healthCheckSamplingStore(ctx); err != nil {
        logger.Warn("sampling store unhealthy; Close may fail to release dist lock")
    }
}

Try / catch

if err := tp.close(ctx); err != nil {
    logger.Error("failed to stop adaptive sampling aggregator", log.Error(err))
    // decide whether to abort shutdown or continue; inspect wrapped cause
    return fmt.Errorf("processor shutdown failed: %w", err)
}

Prevention

When it happens

Trigger: Calling close (collector shutdown or test) while tp.aggregator is non-nil and aggregator.Close() returns an error — e.g. the distributed lock cannot be released or background workers fail to stop within the shutdown deadline.

Common situations: Collector shutdown with the sampling store unreachable; the dist-lock backend (etcd/oteld) down at shutdown time so the lock cannot be released; context/deadline expiring before the aggregator's background loop exits.

Related errors


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

Appendix: source

Thrown at cmd/jaeger/internal/processors/adaptivesampling/processor.go:62

		tp.telset.Logger,
		otelmetrics.NewFactory(tp.telset.MeterProvider),
		parts.DistLock,
		parts.SamplingStore,
	)
	if err != nil {
		return fmt.Errorf("failed to create the adaptive sampling aggregator: %w", err)
	}

	agg.Start()
	tp.aggregator = agg

	return nil
}

func (tp *traceProcessor) close(context.Context) error {
	if tp.aggregator != nil {
		if err := tp.aggregator.Close(); err != nil {
			return fmt.Errorf("failed to stop the adaptive sampling aggregator : %w", err)
		}
	}
	return nil
}

func (tp *traceProcessor) processTraces(_ context.Context, td ptrace.Traces) (ptrace.Traces, error) {
	batches := v1adapter.V1BatchesFromTraces(td)
	for _, batch := range batches {
		for _, span := range batch.Spans {
			if span.Process == nil {
				span.Process = batch.Process
			}
			tp.aggregator.HandleRootSpan(span)
		}
	}
	return td, nil
}

View on GitHub (pinned to 806f444784)