caddyserver/caddy · warning

tracerProvider shutdown error: %w

Error message

tracerProvider shutdown error: %w

What it means

Returned by the tracing module's global tracer-provider cleanup when the last tracing handler is being torn down and tracerProvider.Shutdown(context.Background()) fails. Shutdown flushes any buffered spans to the exporter, so an unreachable or already-closed OTLP endpoint, or an exporter already shut down by a concurrent reload, produces this error. It surfaces during Caddy config unload/reload or process exit, not during request serving.

Source

Thrown at modules/caddyhttp/tracing/tracerprovider.go:68

	t.mu.Lock()
	defer t.mu.Unlock()

	if t.tracerProvidersCounter > 0 {
		t.tracerProvidersCounter--
	}

	if t.tracerProvidersCounter == 0 {
		if t.tracerProvider != nil {
			// tracerProvider.ForceFlush SHOULD be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#forceflush
			if err := t.tracerProvider.ForceFlush(context.Background()); err != nil {
				if c := logger.Check(zapcore.ErrorLevel, "forcing flush"); c != nil {
					c.Write(zap.Error(err))
				}
			}

			// tracerProvider.Shutdown MUST be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown
			if err := t.tracerProvider.Shutdown(context.Background()); err != nil {
				return fmt.Errorf("tracerProvider shutdown error: %w", err)
			}
		}

		t.tracerProvider = nil
	}

	return nil
}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Verify the collector at OTEL_EXPORTER_OTLP_ENDPOINT is reachable from Caddy at shutdown time (curl the endpoint's / health path)
  2. Raise OTEL_EXPORTER_OTLP_TIMEOUT (e.g. 10s or 30s) so the final flush can complete
  3. This error is non-fatal for config load — it is logged/returned during cleanup; if spans are still being delivered, it can be treated as a warning about lost tail spans
  4. Ensure only one Caddy instance writes to the same collector path if the collector rejects duplicate connections

Example fix

# before
OTEL_EXPORTER_OTLP_TIMEOUT=1s

# after
OTEL_EXPORTER_OTLP_TIMEOUT=30s
Defensive patterns

Strategy: try-catch

Try / catch

// During cleanup (e.g. your own wrapper around Caddy runs or module Cleanup):
if err := provider.Shutdown(ctx); err != nil {
    // non-fatal: log and continue teardown; buffered tail spans may be lost
    log.Printf("warn: tracer provider shutdown: %v", err)
}

Prevention

When it happens

Trigger: Config reload or shutdown of the last route using `tracing` while the OTLP collector is down, has closed the connection, or the endpoint URL is wrong — the BatchSpanProcessor's final flush fails inside Shutdown. Also occurs when OTEL_EXPORTER_OTLP_TIMEOUT is too small for a slow collector, or when two reloads race and one shutdown closes the exporter first.

Common situations: Collector container restarting while Caddy reloads config; collector behind a load balancer that drops idle connections; aggressive OTEL_EXPORTER_OTLP_TIMEOUT (e.g. 1s) with a remote collector; CI environments where the tracing backend is a stub.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/437ebdb84f53ef31. Report an issue: GitHub.