{"record":{"id":"a758e8c224650b03","repo":"caddyserver/caddy","slug":"creating-trace-exporter-error-w","errorCode":null,"errorMessage":"creating trace exporter error: %w","messagePattern":"creating trace exporter error: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/tracing/tracer.go","lineNumber":75,"sourceCode":"\t}\n\n\tversion, _ := caddy.Version()\n\tres, err := ot.newResource(caddyhttp.ServerHeader, version)\n\tif err != nil {\n\t\treturn ot, fmt.Errorf(\"creating resource error: %w\", err)\n\t}\n\n\tot.propagators = autoprop.NewTextMapPropagator()\n\n\t// Defer creation of the exporter (and its batch span processor goroutine)\n\t// until we know a new provider is actually needed. When the global provider\n\t// already exists it is reused and these options are discarded; building them\n\t// here unconditionally would leak the exporter and a BatchSpanProcessor\n\t// goroutine on every config reload.\n\ttracerProvider, err := globalTracerProvider.getTracerProvider(func() ([]sdktrace.TracerProviderOption, error) {\n\t\ttraceExporter, err := autoexport.NewSpanExporter(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"creating trace exporter error: %w\", err)\n\t\t}\n\n\t\treturn []sdktrace.TracerProviderOption{\n\t\t\tsdktrace.WithBatcher(traceExporter),\n\t\t\tsdktrace.WithResource(res),\n\t\t}, nil\n\t})\n\tif err != nil {\n\t\treturn ot, err\n\t}\n\n\tot.handler = otelhttp.NewHandler(http.HandlerFunc(ot.serveHTTP),\n\t\tot.spanName,\n\t\totelhttp.WithTracerProvider(tracerProvider),\n\t\totelhttp.WithPropagators(ot.propagators),\n\t\totelhttp.WithSpanNameFormatter(ot.spanNameFormatter),\n\t)\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/tracing/tracer.go#L57-L93","documentation":"Thrown by the Caddy HTTP tracing module while provisioning when autoexport.NewSpanExporter(ctx) fails to build an OpenTelemetry span exporter. autoexport picks the exporter from OTEL_TRACES_EXPORTER and the wire protocol from OTEL_EXPORTER_OTLP_PROTOCOL, so an unknown exporter/protocol name, an exporter not compiled into the binary, or an invalid OTLP endpoint causes this. The underlying cause is wrapped with %w, so the chained error names the exact problem.","triggerScenarios":"Running Caddy with the `tracing` directive while OTEL_TRACES_EXPORTER is set to an unregistered name (not otlp/console/none), or OTEL_EXPORTER_OTLP_PROTOCOL is set to grpc without the gRPC exporter available, or OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_TRACES_OTLP_ENDPOINT has a malformed URL (missing scheme, bad port). autoexport.NewSpanExporter(ctx) returns a non-nil error and the wrapper fires at modules/caddyhttp/tracing/tracer.go:75.","commonSituations":"Env vars copied from another OTel-instrumented service into the Caddy unit file or container; protocol set to `grpc` when the OTLP receiver only accepts HTTP protobuf (or the grpc plugin tag was not built); typos like `http/proto` instead of `http/protobuf`; an empty OTEL_EXPORTER_OTLP_ENDPOINT after an env refactor.","solutions":["Inspect the wrapped cause in the log line `creating trace exporter error:` — autoexport errors name the offending env var (e.g. `invalid value for environment variable \"OTEL_EXPORTER_OTLP_PROTOCOL\"`)","Set OTEL_EXPORTER_OTLP_PROTOCOL to a supported value: grpc, http/protobuf, or http/json (and make sure the matching exporter is compiled in)","Set OTEL_TRACES_EXPORTER to otlp (or unset it; otlp is the default) and verify OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_TRACES_OTLP_ENDPOINT is a full URL like https://collector:4318","If no collector is intended, remove the `tracing` directive or set OTEL_TRACES_EXPORTER=none where supported","After fixing env vars, fully restart Caddy (config reload reuses a global provider and may keep the old state)"],"exampleFix":"# before (unit file / container env)\nOTEL_EXPORTER_OTLP_PROTOCOL=http/proto\nOTEL_TRACES_EXPORTER=otlp-grpc\n\n# after\nOTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\nOTEL_TRACES_EXPORTER=otlp\nOTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318","handlingStrategy":"validation","validationCode":"// Before enabling the tracing directive, verify exporter env config:\nfunc checkExporterEnv() error {\n    if p := os.Getenv(\"OTEL_EXPORTER_OTLP_PROTOCOL\"); p != \"\" {\n        switch p {\n        case \"grpc\", \"http/protobuf\", \"http/json\":\n        default:\n            return fmt.Errorf(\"unsupported OTEL_EXPORTER_OTLP_PROTOCOL %q\", p)\n        }\n    }\n    if e := os.Getenv(\"OTEL_TRACES_EXPORTER\"); e != \"\" && e != \"otlp\" && e != \"none\" {\n        return fmt.Errorf(\"unsupported OTEL_TRACES_EXPORTER %q\", e)\n    }\n    if ep := os.Getenv(\"OTEL_EXPORTER_OTLP_ENDPOINT\"); ep != \"\" {\n        if _, err := url.Parse(ep); err != nil {\n            return fmt.Errorf(\"bad OTEL_EXPORTER_OTLP_ENDPOINT: %w\", err)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// The error is returned from Provision; catch it at config load and log the wrapped cause:\nif err := tracerModule.Provision(ctx); err != nil {\n    if strings.Contains(err.Error(), \"creating trace exporter error\") {\n        log.Printf(\"tracing disabled: fix OTEL env vars: %v\", err)\n    }\n    return err\n}","preventionTips":["Validate OTEL_* env vars in the container/unit-file template before deploying Caddy","Pin OTEL_EXPORTER_OTLP_PROTOCOL explicitly to http/protobuf in managed deployments","Run `caddy validate --config` in CI with the same env vars the service runs with"],"tags":["tracing","opentelemetry","environment","config","caddyhttp"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}