{"record":{"id":"eee99ecb71c68a41","repo":"caddyserver/caddy","slug":"creating-otlp-metric-reader-w","errorCode":null,"errorMessage":"creating OTLP metric reader: %w","messagePattern":"creating OTLP metric reader: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/metrics.go","lineNumber":193,"sourceCode":"\t}\n\n\t// Register a Prometheus -> OpenTelemetry bridge against the process-wide\n\t// Prometheus registry as the *default* source the NewMetricReader below\n\t// will read from.\n\t//\n\t// NB: despite the \"With*\" naming, autoexport.WithFallbackMetricProducer is\n\t// a package-level setter (it returns nothing) — it mutates autoexport's\n\t// internal producer registry and takes effect on the very next call to\n\t// NewMetricReader. It is NOT a MetricOption and must not be passed as one.\n\t// Users can still override the source by setting OTEL_METRICS_PRODUCERS.\n\treg := ctx.GetMetricsRegistry()\n\tautoexport.WithFallbackMetricProducer(func(context.Context) (sdkmetric.Producer, error) {\n\t\treturn otelprom.NewMetricProducer(otelprom.WithGatherer(reg)), nil\n\t})\n\n\treader, err := autoexport.NewMetricReader(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating OTLP metric reader: %w\", err)\n\t}\n\n\tversion, _ := caddy.Version()\n\tres, err := resource.Merge(resource.Default(), resource.NewSchemaless(\n\t\tsemconv.WebEngineName(ServerHeader),\n\t\tsemconv.WebEngineVersion(version),\n\t))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building OTLP metrics resource: %w\", err)\n\t}\n\n\tm.meterProvider = sdkmetric.NewMeterProvider(\n\t\tsdkmetric.WithResource(res),\n\t\tsdkmetric.WithReader(reader),\n\t)\n\n\treturn nil\n}","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/metrics.go#L175-L211","documentation":"When metrics are configured for export (metrics { ... } with OTLP/autoexport), AdminMetrics/InstrumentationMetrics provisioning calls autoexport.NewMetricReader(ctx), which reads OTEL_METRICS_EXPORTER and related OTEL_EXPORTER_OTLP_* environment variables. Failures — unknown exporter name, no exporter available for the requested protocol — are wrapped as 'creating OTLP metric reader'. Note the code first installs a fallback producer reading Caddy's own Prometheus registry; OTEL_METRICS_PRODUCERS can override it.","triggerScenarios":"OTEL_METRICS_EXPORTER set to an unsupported value (e.g. 'otlp' when the build lacks it, or a typo like 'otlpgrp'); OTEL_EXPORTER_OTLP_PROTOCOL/OTEL_EXPORTER_OTLP_METRICS_PROTOCOL set to an unregistered protocol (e.g. 'http/protobuf' in a build without it); env vars set globally leaking into the Caddy process.","commonSituations":"Kubernetes pods inheriring OpenTelemetry operator sidecar env vars; CI shells with stray OTEL_* exports; upgrading OTel libraries that renamed valid exporter values; enabling `metrics` blocks on servers where ops intended Prometheus scrape only.","solutions":["Check OTEL_METRICS_EXPORTER — use a supported value (e.g. otlp, prometheus, none per your OTel SDK version) or unset it.","Verify OTEL_EXPORTER_OTLP_PROTOCOL / OTEL_EXPORTER_OTLP_METRICS_PROTOCOL match a protocol the build supports (grpc vs http/protobuf).","Unset conflicting OTEL_* variables in the service unit/entrypoint (env -u OTEL_METRICS_EXPORTER ...) if OTLP export was never intended.","Confirm the endpoint env (OTEL_EXPORTER_OTLP_ENDPOINT / _METRICS_ENDPOINT) is reachable and well-formed."],"exampleFix":"# before\nexport OTEL_METRICS_EXPORTER=otlpgrp\n\n# after\nexport OTEL_METRICS_EXPORTER=otlp\nexport OTEL_EXPORTER_OTLP_PROTOCOL=grpc","handlingStrategy":"validation","validationCode":"# Shell: verify exporter env before starting Caddy\nexport OTEL_METRICS_EXPORTER=otlp   # or prometheus / none, per your OTel build\nexport OTEL_EXPORTER_OTLP_PROTOCOL=grpc\nenv | grep '^OTEL_' # audit every variable for typos","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Audit OTEL_* env vars in the service unit or container spec.","Unset OTel variables in environments that only want Prometheus scraping.","Keep endpoint and protocol variables consistent (_METRICS_PROTOCOL overrides _PROTOCOL)."],"tags":["caddy","metrics","opentelemetry","environment","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}