block/buzz · critical

failed to install rustls crypto provider

Error message

failed to install rustls crypto provider

What it means

rustls 0.23 requires exactly one process-default CryptoProvider. main() installs ring's provider because both ring and aws-lc-rs are compiled in transitively and rustls cannot auto-select. install_default() returns Err only when a default provider is ALREADY installed — the first successful call wins — so this expect means something else in the process set a provider first, and the relay aborts at startup.

Source

Thrown at crates/buzz-relay/src/main.rs:104

        }
    }

    fn allows(&self, _community_id: &Uuid) -> bool {
        matches!(self, Self::All)
    }
}

const USAGE_METRICS_LOCK_KEY: i64 = 0x4255_5A5A_4D45_5452;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Install the ring CryptoProvider for rustls. Required before any rustls
    // TLS connection (rediss:// to ElastiCache, wss://, S3 over TLS): both
    // aws-lc-rs and ring are compiled in transitively, so rustls can't
    // auto-select a provider and would panic at first use without this.
    rustls::crypto::ring::default_provider()
        .install_default()
        .expect("failed to install rustls crypto provider");

    // JSON-only structured logs — simple, machine-parseable, CAKE-compatible.
    // If OTEL_EXPORTER_OTLP_ENDPOINT is set, also attach an OpenTelemetry tracing
    // layer that exports spans via OTLP gRPC alongside the JSON stdout logs.
    //
    // Build a single shared Resource (service.name=buzz-relay by default, overridable
    // via OTEL_SERVICE_NAME) for the trace provider so that Datadog can identify
    // spans under the correct service identity.
    let resource = telemetry::service_resource();
    let tracer_init = telemetry::try_init_tracer(resource.clone());
    let otel_enabled = matches!(&tracer_init, telemetry::TracerInit::Enabled(_));
    let otel_layer = match &tracer_init {
        telemetry::TracerInit::Enabled(p) => {
            use opentelemetry::trace::TracerProvider as _;
            Some(tracing_opentelemetry::layer().with_tracer(p.tracer("buzz-relay")))
        }
        _ => None,
    };

View on GitHub (pinned to eed74bde2f)

Solutions

  1. Guard the install: only call install_default() when CryptoProvider::get_default().is_none()
  2. Locate and remove the competing install_default() call (check test setup helpers and newly added dependencies)
  3. Pin one provider across the workspace via rustls crate features (default-features = false, features = ["ring"]) so no dependency auto-installs another

Example fix

// before
rustls::crypto::ring::default_provider()
    .install_default()
    .expect("failed to install rustls crypto provider");

// after
if rustls::crypto::CryptoProvider::get_default().is_none() {
    rustls::crypto::ring::default_provider()
        .install_default()
        .expect("failed to install rustls crypto provider");
}
Defensive patterns

Strategy: validation

Validate before calling

// before any rustls use in tests or embedders:
if rustls::crypto::CryptoProvider::get_default().is_none() {
    rustls::crypto::ring::default_provider()
        .install_default()
        .expect("failed to install rustls crypto provider");
}

Try / catch

match rustls::crypto::ring::default_provider().install_default() {
    Ok(()) => {}
    Err(already) => tracing::debug!("rustls provider already installed: {already:?}"),
}

Prevention

When it happens

Trigger: A dependency or test setup already called CryptoProvider::install_default() (commonly aws_lc_rs::default_provider()) before relay main ran; embedding or invoking the relay init path twice in one process (tests, sprig-style harnesses) so the second install fails.

Common situations: Adding a crate that transitively installs a rustls provider; integration tests that build rustls-based clients (redis/tokio-postgres/reqwest helpers) and also run relay startup code; rustls version upgrades flipping default provider features.

Related errors


AI-assisted analysis of block/buzz@eed74bde2f (2026-08-20). Data as JSON: /api/errors/83202d03fa31ba61. Report an issue: GitHub.