actix/actix-web · critical
Failed to find native root certificates
Error message
Failed to find native root certificates
What it means
Raised by `.expect("Failed to find native root certificates")` at awc/src/client/connector.rs:122 inside `build_tls`, which only compiles when the `rustls-0_23-native-roots` Cargo feature is on. On `Connector` construction (including via `Client::default()`/`Client::builder().finish()`) the library calls `rustls_0_23::native_roots_cert_store()`, which uses the `rustls-native-certs` crate to read the host OS trust store (macOS Keychain, Windows cert store, or `/etc/ssl/certs` on Linux). If that read returns `Err`, `.expect()` panics, crashing the process at startup with no TLS possible.
Source
Thrown at awc/src/client/connector.rs:122
connector: TcpConnector::new(resolver::resolver()).service(),
config: ConnectorConfig::default(),
tls: Self::build_tls(vec![b"h2".to_vec(), b"http/1.1".to_vec()]),
}
}
cfg_if::cfg_if! {
if #[cfg(any(feature = "rustls-0_23-webpki-roots", feature = "rustls-0_23-native-roots"))] {
/// Build TLS connector with Rustls v0.23, based on supplied ALPN protocols.
///
/// Note that if other TLS crate features are enabled, Rustls v0.23 will be used.
fn build_tls(protocols: Vec<Vec<u8>>) -> OurTlsConnector {
use actix_tls::connect::rustls_0_23::{self, reexports::ClientConfig};
cfg_if::cfg_if! {
if #[cfg(feature = "rustls-0_23-webpki-roots")] {
let certs = rustls_0_23::webpki_roots_cert_store();
} else if #[cfg(feature = "rustls-0_23-native-roots")] {
let certs = rustls_0_23::native_roots_cert_store().expect("Failed to find native root certificates");
}
}
let mut config = ClientConfig::builder()
.with_root_certificates(certs)
.with_no_client_auth();
config.alpn_protocols = protocols;
OurTlsConnector::Rustls023(std::sync::Arc::new(config))
}
} else if #[cfg(any(feature = "rustls-0_22-webpki-roots", feature = "rustls-0_22-native-roots"))] {
/// Build TLS connector with Rustls v0.22, based on supplied ALPN protocols.
fn build_tls(protocols: Vec<Vec<u8>>) -> OurTlsConnector {
use actix_tls::connect::rustls_0_22::{self, reexports::ClientConfig};
cfg_if::cfg_if! {
if #[cfg(feature = "rustls-0_22-webpki-roots")] {View on GitHub (pinned to 937960ca67)
Solutions
- Install the OS CA bundle: Debian/Ubuntu `apt-get update && apt-get install -y ca-certificates`; Alpine `apk add --no-cache ca-certificates`; Fedora/RHEL `dnf install -y ca-certificates`.
- Switch Cargo features from `rustls-0_23-native-roots` to `rustls-0_23-webpki-roots`, which embeds the Mozilla root program at compile time and removes any runtime OS dependency (best for containers/cross-compile).
- If you must use native roots, point `SSL_CERT_FILE` (e.g. `/etc/ssl/certs/ca-certificates.crt`) or `SSL_CERT_DIR` at a valid PEM bundle the process can read.
- Verify the bundle is readable by the runtime user (`ls -l /etc/ssl/certs/ca-certificates.crt`) and run `update-ca-certificates` / `ca-certificates update` to regenerate it.
Example fix
# before (awc/Cargo.toml features)
awc = { features = ["rustls-0_23-native-roots"] }
# after - use bundled Mozilla roots, no OS store dependency
awc = { features = ["rustls-0_23-webpki-roots"] }
# or, in a Dockerfile, ensure the bundle is present
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/* Defensive patterns
Strategy: validation
Validate before calling
// Run before constructing an awc::Connector with rustls-0_23-native-roots.
fn native_roots_available() -> bool {
#[cfg(target_os = "linux")]
{
let candidates = [
std::env::var("SSL_CERT_FILE").unwrap_or_default(),
"/etc/ssl/certs/ca-certificates.crt".into(),
"/etc/pki/tls/certs/ca-bundle.crt".into(),
];
candidates.iter().any(|p| !p.is_empty() && std::path::Path::new(p).exists())
}
#[cfg(not(target_os = "linux"))]
{ true } // Keychain / Windows store; assume present
}
if !native_roots_available() {
panic!("Refusing to build awc::Connector: no native CA bundle found. Install ca-certificates or enable rustls-0_23-webpki-roots.");
} Try / catch
// The error is a panic via .expect(), so std::try-catch cannot intercept it.
// Best defense is validation + feature fallback. As a last-resort guard you can
// catch_unwind, but prefer fixing the environment:
use std::panic;
let connector = panic::catch_unwind(|| awc::Connector::new());
match connector {
Ok(c) => c,
Err(_) => { /* log and exit; fix the CA bundle or switch features */ }
} Prevention
- Prefer the `rustls-0_23-webpki-roots` feature for portable/containerized builds so the root set is compiled in.
- Bake `ca-certificates` into base Docker images used by the app.
- In CI, assert `test -r /etc/ssl/certs/ca-certificates.crt` (or platform equivalent) before running the suite.
- Pin awc features in Cargo.toml and review them in code review so `*-native-roots` is a deliberate choice.
When it happens
Trigger: Constructing an `awc::Connector` or `awc::Client` while the crate was compiled with the `rustls-0_23-native-roots` feature, on a host whose system certificate store returns an error when `rustls-native-certs` reads it (empty result, unreadable bundle, or unsupported platform). The panic fires synchronously during the `Connector::new()` / `build_tls` call, before any request is sent.
Common situations: Minimal Docker images (alpine, distroless, `scratch`) that ship without a CA bundle; CI runners with stripped/missing `/etc/ssl/certs/ca-certificates.crt`; locked-down environments where the cert files exist but are not readable by the process user; cross-compilation targets where native cert loading is unsupported; systems where `ca-certificates` was never installed or was purged.
Related errors
- failed to build Hickory DNS resolver
- Unsupported HTTP version: {:?}.
- actix-http client only supports versions http/1.1 & http/2
- All default headers must be added before cloning.
- Invalid header name
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/88684d446ec1ddf9.json.
Report an issue: GitHub.