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
- Verify the collector at OTEL_EXPORTER_OTLP_ENDPOINT is reachable from Caddy at shutdown time (curl the endpoint's / health path)
- Raise OTEL_EXPORTER_OTLP_TIMEOUT (e.g. 10s or 30s) so the final flush can complete
- 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
- 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
- Keep the collector reachable during Caddy reloads/shutdown windows
- Set OTEL_EXPORTER_OTLP_TIMEOUT generously (10-30s) so the final flush completes
- Treat shutdown errors as data-loss warnings for buffered spans, not as config errors
- Avoid rapid successive config reloads that race provider teardown
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
- tracerProvider shutdown: %w
- %v; additionally, aborting app %s: %v
- server graceful shutdown %ds timeout
- creating resource error: %w
- creating trace exporter error: %w
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/437ebdb84f53ef31.
Report an issue: GitHub.