{"record":{"id":"83202d03fa31ba61","repo":"block/buzz","slug":"failed-to-install-rustls-crypto-provider-83202d","errorCode":null,"errorMessage":"failed to install rustls crypto provider","messagePattern":"failed to install rustls crypto provider","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/buzz-relay/src/main.rs","lineNumber":104,"sourceCode":"        }\n    }\n\n    fn allows(&self, _community_id: &Uuid) -> bool {\n        matches!(self, Self::All)\n    }\n}\n\nconst USAGE_METRICS_LOCK_KEY: i64 = 0x4255_5A5A_4D45_5452;\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n    // Install the ring CryptoProvider for rustls. Required before any rustls\n    // TLS connection (rediss:// to ElastiCache, wss://, S3 over TLS): both\n    // aws-lc-rs and ring are compiled in transitively, so rustls can't\n    // auto-select a provider and would panic at first use without this.\n    rustls::crypto::ring::default_provider()\n        .install_default()\n        .expect(\"failed to install rustls crypto provider\");\n\n    // JSON-only structured logs — simple, machine-parseable, CAKE-compatible.\n    // If OTEL_EXPORTER_OTLP_ENDPOINT is set, also attach an OpenTelemetry tracing\n    // layer that exports spans via OTLP gRPC alongside the JSON stdout logs.\n    //\n    // Build a single shared Resource (service.name=buzz-relay by default, overridable\n    // via OTEL_SERVICE_NAME) for the trace provider so that Datadog can identify\n    // spans under the correct service identity.\n    let resource = telemetry::service_resource();\n    let tracer_init = telemetry::try_init_tracer(resource.clone());\n    let otel_enabled = matches!(&tracer_init, telemetry::TracerInit::Enabled(_));\n    let otel_layer = match &tracer_init {\n        telemetry::TracerInit::Enabled(p) => {\n            use opentelemetry::trace::TracerProvider as _;\n            Some(tracing_opentelemetry::layer().with_tracer(p.tracer(\"buzz-relay\")))\n        }\n        _ => None,\n    };","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/block/buzz/blob/eed74bde2f4797714335ac10c56c0b0244c1def4/crates/buzz-relay/src/main.rs#L86-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Guard the install: only call install_default() when CryptoProvider::get_default().is_none()","Locate and remove the competing install_default() call (check test setup helpers and newly added dependencies)","Pin one provider across the workspace via rustls crate features (default-features = false, features = [\"ring\"]) so no dependency auto-installs another"],"exampleFix":"// before\nrustls::crypto::ring::default_provider()\n    .install_default()\n    .expect(\"failed to install rustls crypto provider\");\n\n// after\nif rustls::crypto::CryptoProvider::get_default().is_none() {\n    rustls::crypto::ring::default_provider()\n        .install_default()\n        .expect(\"failed to install rustls crypto provider\");\n}","handlingStrategy":"validation","validationCode":"// before any rustls use in tests or embedders:\nif rustls::crypto::CryptoProvider::get_default().is_none() {\n    rustls::crypto::ring::default_provider()\n        .install_default()\n        .expect(\"failed to install rustls crypto provider\");\n}","typeGuard":null,"tryCatchPattern":"match rustls::crypto::ring::default_provider().install_default() {\n    Ok(()) => {}\n    Err(already) => tracing::debug!(\"rustls provider already installed: {already:?}\"),\n}","preventionTips":["Have exactly one install site for the process-default CryptoProvider and guard it with get_default()","Align the whole workspace on one rustls provider via crate features so dependencies cannot auto-install a competing one","In test binaries that also use rustls clients, run the same guarded install in the test harness setup"],"tags":["rust","rustls","tls","crypto-provider","startup","ring"],"backgroundTag":"rustls-crypto-provider-conflict","analyzedSha":"eed74bde2f4797714335ac10c56c0b0244c1def4","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}