linera-io/linera-protocol · error

Failed to create OTLP exporter

Error message

Failed to create OTLP exporter

What it means

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.

Source

Thrown at linera-service/src/tracing/opentelemetry.rs:151

        Some(ep) if !ep.is_empty() => ep.to_string(),
        _ => match std::env::var("LINERA_OTLP_EXPORTER_ENDPOINT") {
            Ok(ep) if !ep.is_empty() => ep,
            _ => {
                crate::tracing::init(log_name);
                return;
            }
        },
    };

    let resource = Resource::builder()
        .with_service_name(log_name.to_string())
        .build();

    let exporter = SpanExporter::builder()
        .with_tonic()
        .with_endpoint(endpoint)
        .build()
        .expect("Failed to create OTLP exporter");

    // Configure batch processor for high-throughput scenarios
    // Larger queue (16k instead of 2k default) to handle benchmark load
    // Faster export (100ms instead of 5s default) to prevent queue buildup
    let batch_config = opentelemetry_sdk::trace::BatchConfigBuilder::default()
        .with_max_queue_size(16384) // 8x default, enough for 8 shards under load
        .with_max_export_batch_size(2048) // Larger batches for efficiency
        .with_scheduled_delay(std::time::Duration::from_millis(100)) // Fast export to prevent queue buildup
        .build();

    let batch_processor = BatchSpanProcessor::new(exporter, batch_config);

    let tracer_provider = SdkTracerProvider::builder()
        .with_resource(resource)
        .with_span_processor(batch_processor)
        .with_sampler(opentelemetry_sdk::trace::Sampler::AlwaysOn)
        .build();

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Fix LINERA_OTLP_EXPORTER_ENDPOINT to a fully-qualified tonic-compatible URL with an explicit port, e.g. http://localhost:4317
  2. Unset LINERA_OTLP_EXPORTER_ENDPOINT (or pass None to init) so tracing falls back to the non-OTLP initializer instead of panicking
  3. Inspect the exact value with `printf '%s' "$LINERA_OTLP_EXPORTER_ENDPOINT" | od -c` to spot hidden whitespace/newlines, then re-export it cleanly
  4. 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

Example fix

// before
export LINERA_OTLP_EXPORTER_ENDPOINT=localhost:4317  // no scheme -> exporter build fails, init panics

// after
export LINERA_OTLP_EXPORTER_ENDPOINT=http://localhost:4317
// or disable OTLP entirely:
unset LINERA_OTLP_EXPORTER_ENDPOINT
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate the endpoint before enabling OTLP
fn valid_otlp_endpoint(s: &str) -> bool {
    let t = s.trim();
    (t.starts_with("http://") || t.starts_with("https://")) && !t.chars().any(char::is_whitespace)
}

let endpoint = std::env::var("LINERA_OTLP_EXPORTER_ENDPOINT").ok();
let endpoint = endpoint.filter(|ep| !ep.is_empty() && valid_otlp_endpoint(ep));
tracing_init(log_name, endpoint.as_deref()); // None -> OTLP skipped, no panic

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/5bcfa1a198cd820a. Report an issue: GitHub.