stalwartlabs/stalwart · critical

failed to install aws-lc-rs as the default rustls crypto pro

Error message

failed to install aws-lc-rs as the default rustls crypto provider

What it means

Rustls requires exactly one process-wide default crypto provider. This panic fires when `aws_lc_rs::default_provider().install_default()` returns Err, which happens only if a default provider was already installed (or another provider was installed first, e.g. by a dependency using ring). The process cannot start because TLS cannot be configured as intended.

Source

Thrown at crates/main/src/main.rs:38

use trc::Collector;
use utils::wait_for_shutdown;

#[cfg(feature = "dev_mode")]
pub mod test_data;

#[cfg(not(any(target_env = "msvc", target_os = "freebsd")))]
use tikv_jemallocator::Jemalloc;

#[cfg(not(any(target_env = "msvc", target_os = "freebsd")))]
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    // Install AWS-LC-RS as the default Rustls crypto provider
    rustls::crypto::aws_lc_rs::default_provider()
        .install_default()
        .expect("failed to install aws-lc-rs as the default rustls crypto provider");

    // Build the shared outbound TLS configurations
    utils::http::init_shared_tls_configs();

    // Load config and apply macros
    let mut init = Box::pin(BootManager::init()).await;

    // Migrate database
    if let Err(err) = migration::try_migrate(&init.inner.build_server()).await {
        trc::event!(
            Server(trc::ServerEvent::StartupError),
            Details = "Failed to migrate database, aborting startup.",
            Reason = err,
        );
        return Ok(());
    }

    // Init services

View on GitHub (pinned to e962003857)

Solutions

  1. Ensure no dependency installs a rustls provider before main runs; check Cargo features for duplicate crypto provider crates (ring + aws-lc-rs)
  2. If a provider may already be installed, replace install_default().expect() with try_install() or check the Result instead of panicking
  3. Explicitly pass the provider to ClientConfig/ServerConfig builders instead of relying on the process default
  4. Update dependencies so only one TLS crypto provider is active

Example fix

// before
rustls::crypto::aws_lc_rs::default_provider()
    .install_default()
    .expect("failed to install aws-lc-rs as the default rustls crypto provider");
// after
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
Defensive patterns

Strategy: fallback

Try / catch

// install_default returns Result; don't panic if a provider exists:
if rustls::crypto::CryptoProvider::get_default().is_none() {
    rustls::crypto::aws_lc_rs::default_provider()
        .install_default()
        .expect("failed to install default crypto provider");
}

Prevention

When it happens

Trigger: Calling main after some other code path (a dependency, an earlier init, or duplicate installation) has already installed a rustls CryptoProvider via `install_default()`, or having two provider installations in the binary.

Common situations: A dependency (e.g. a library that installs the ring provider) is pulled in and initializes before main; the binary is built with both ring and aws-lc-rs features and some crate initializes ring first; duplicate install calls in embedded/test setups.

Related errors


AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06). Data as JSON: /api/errors/b1da277453923300. Report an issue: GitHub.