{"record":{"id":"5bcfa1a198cd820a","repo":"linera-io/linera-protocol","slug":"failed-to-create-otlp-exporter","errorCode":null,"errorMessage":"Failed to create OTLP exporter","messagePattern":"Failed to create OTLP exporter","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-service/src/tracing/opentelemetry.rs","lineNumber":151,"sourceCode":"        Some(ep) if !ep.is_empty() => ep.to_string(),\n        _ => match std::env::var(\"LINERA_OTLP_EXPORTER_ENDPOINT\") {\n            Ok(ep) if !ep.is_empty() => ep,\n            _ => {\n                crate::tracing::init(log_name);\n                return;\n            }\n        },\n    };\n\n    let resource = Resource::builder()\n        .with_service_name(log_name.to_string())\n        .build();\n\n    let exporter = SpanExporter::builder()\n        .with_tonic()\n        .with_endpoint(endpoint)\n        .build()\n        .expect(\"Failed to create OTLP exporter\");\n\n    // Configure batch processor for high-throughput scenarios\n    // Larger queue (16k instead of 2k default) to handle benchmark load\n    // Faster export (100ms instead of 5s default) to prevent queue buildup\n    let batch_config = opentelemetry_sdk::trace::BatchConfigBuilder::default()\n        .with_max_queue_size(16384) // 8x default, enough for 8 shards under load\n        .with_max_export_batch_size(2048) // Larger batches for efficiency\n        .with_scheduled_delay(std::time::Duration::from_millis(100)) // Fast export to prevent queue buildup\n        .build();\n\n    let batch_processor = BatchSpanProcessor::new(exporter, batch_config);\n\n    let tracer_provider = SdkTracerProvider::builder()\n        .with_resource(resource)\n        .with_span_processor(batch_processor)\n        .with_sampler(opentelemetry_sdk::trace::Sampler::AlwaysOn)\n        .build();\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-service/src/tracing/opentelemetry.rs#L133-L169","documentation":"The linera-service tracing initializer builds an OpenTelemetry OTLP span exporter (gRPC/tonic transport) from an endpoint taken from the `otlp_endpoint` parameter or the LINERA_OTLP_EXPORTER_ENDPOINT environment variable. `SpanExporter::builder().with_tonic().with_endpoint(endpoint).build()` returns a Result because it parses and validates the endpoint URL and exporter configuration, and `.expect(\"Failed to create OTLP exporter\")` crashes the process during tracing init when construction fails. It can only fire when OTLP is explicitly enabled: with no endpoint configured, init() falls back to the plain non-OTLP initializer and returns early.","triggerScenarios":"Calling `tracing::init(log_name, Some(ep))` with a non-empty endpoint, or starting a linera-service binary with LINERA_OTLP_EXPORTER_ENDPOINT set to a value the tonic exporter rejects: missing scheme (`localhost:4317` instead of `http://localhost:4317`), an unsupported protocol, stray whitespace/trailing newline/quotes, or an endpoint rejected by the opentelemetry-otlp version in use.","commonSituations":"Copying a collector address from OTLP docs (bare host:port or `grpc://...`) into LINERA_OTLP_EXPORTER_ENDPOINT; CI secrets that append a trailing newline; upgrading opentelemetry-otlp so endpoint parsing becomes stricter; enabling the variable in an environment where it used to be unset.","solutions":["Fix LINERA_OTLP_EXPORTER_ENDPOINT to a fully-qualified tonic-compatible URL with an explicit port, e.g. http://localhost:4317","Unset LINERA_OTLP_EXPORTER_ENDPOINT (or pass None to init) so tracing falls back to the non-OTLP initializer instead of panicking","Inspect the exact value with `printf '%s' \"$LINERA_OTLP_EXPORTER_ENDPOINT\" | od -c` to spot hidden whitespace/newlines, then re-export it cleanly","If the URL looks valid, check the opentelemetry-otlp crate version and its tonic feature flags: some versions reject endpoints without an explicit port or with non-http schemes"],"exampleFix":"// before\nexport LINERA_OTLP_EXPORTER_ENDPOINT=localhost:4317  // no scheme -> exporter build fails, init panics\n\n// after\nexport LINERA_OTLP_EXPORTER_ENDPOINT=http://localhost:4317\n// or disable OTLP entirely:\nunset LINERA_OTLP_EXPORTER_ENDPOINT","handlingStrategy":"validation","validationCode":"// Rust: validate the endpoint before enabling OTLP\nfn valid_otlp_endpoint(s: &str) -> bool {\n    let t = s.trim();\n    (t.starts_with(\"http://\") || t.starts_with(\"https://\")) && !t.chars().any(char::is_whitespace)\n}\n\nlet endpoint = std::env::var(\"LINERA_OTLP_EXPORTER_ENDPOINT\").ok();\nlet endpoint = endpoint.filter(|ep| !ep.is_empty() && valid_otlp_endpoint(ep));\ntracing_init(log_name, endpoint.as_deref()); // None -> OTLP skipped, no panic","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always configure LINERA_OTLP_EXPORTER_ENDPOINT as a full http:// or https:// URL with an explicit port","In CI, inspect env vars once with od -c / cat -A to catch trailing newlines injected by secrets","Leave the endpoint unset in environments without a collector — the exporter is then never built"],"tags":["opentelemetry","otlp","tracing","endpoint","rust"],"backgroundTag":"invalid-endpoint-url","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}