{"record":{"id":"88684d446ec1ddf9","repo":"actix/actix-web","slug":"failed-to-find-native-root-certificates","errorCode":null,"errorMessage":"Failed to find native root certificates","messagePattern":"Failed to find native root certificates","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"awc/src/client/connector.rs","lineNumber":122,"sourceCode":"            connector: TcpConnector::new(resolver::resolver()).service(),\n            config: ConnectorConfig::default(),\n            tls: Self::build_tls(vec![b\"h2\".to_vec(), b\"http/1.1\".to_vec()]),\n        }\n    }\n\n    cfg_if::cfg_if! {\n        if #[cfg(any(feature = \"rustls-0_23-webpki-roots\", feature = \"rustls-0_23-native-roots\"))] {\n            /// Build TLS connector with Rustls v0.23, based on supplied ALPN protocols.\n            ///\n            /// Note that if other TLS crate features are enabled, Rustls v0.23 will be used.\n            fn build_tls(protocols: Vec<Vec<u8>>) -> OurTlsConnector {\n                use actix_tls::connect::rustls_0_23::{self, reexports::ClientConfig};\n\n                cfg_if::cfg_if! {\n                    if #[cfg(feature = \"rustls-0_23-webpki-roots\")] {\n                        let certs = rustls_0_23::webpki_roots_cert_store();\n                    } else if #[cfg(feature = \"rustls-0_23-native-roots\")] {\n                        let certs = rustls_0_23::native_roots_cert_store().expect(\"Failed to find native root certificates\");\n                    }\n                }\n\n                let mut config = ClientConfig::builder()\n                    .with_root_certificates(certs)\n                    .with_no_client_auth();\n\n                config.alpn_protocols = protocols;\n\n                OurTlsConnector::Rustls023(std::sync::Arc::new(config))\n            }\n        } else if #[cfg(any(feature = \"rustls-0_22-webpki-roots\", feature = \"rustls-0_22-native-roots\"))] {\n            /// Build TLS connector with Rustls v0.22, based on supplied ALPN protocols.\n            fn build_tls(protocols: Vec<Vec<u8>>) -> OurTlsConnector {\n                use actix_tls::connect::rustls_0_22::{self, reexports::ClientConfig};\n\n                cfg_if::cfg_if! {\n                    if #[cfg(feature = \"rustls-0_22-webpki-roots\")] {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/actix/actix-web/blob/4d435abc281842f3cbee165b6cde739e001d3a25/awc/src/client/connector.rs#L104-L140","documentation":"This is a panic (via .expect) raised during awc Connector construction inside build_tls when the `rustls-0_23-native-roots` Cargo feature is enabled. The code calls `rustls_0_23::native_roots_cert_store().expect(\"Failed to find native root certificates\")` (connector.rs:122), which reads the operating system's trust store. If that load returns an error (no readable CA bundle), the .expect panics. The API doc on Connector::new (connector.rs:93-94) explicitly warns: when rustls-0_23-native-roots is enabled and the runtime system has no native root certificates, this method will panic.","triggerScenarios":"Enabling awc's `rustls-0_23-native-roots` feature and constructing a client/connector (`awc::Client::new()`, `awc::Connector::new()`, or anything that builds the default TLS connector) on a system whose native root certificate store cannot be read. The panic fires at startup, on the first construction of Connector (during build_tls -> native_roots_cert_store), before any network call is attempted.","commonSituations":"Running in minimal Docker images such as `scratch`, `distroless`, or Alpine Linux without the ca-certificates package installed; containers where /etc/ssl/certs/ca-certificates.crt is absent or empty; stripped CI images; cross-compilation targets or embedded environments without an OS trust store; Windows/macOS dev machines are usually fine, but Linux containers frequently lack the bundle.","solutions":["Install the OS CA bundle in the container: on Debian/Ubuntu add `ca-certificates`; on Alpine add `apk add --no-cache ca-certificates` (and update-ca-certificates). This makes native_roots_cert_store succeed.","Switch the awc Cargo feature from `rustls-0_23-native-roots` to `rustls-0_23-webpki-roots`, which bundles Mozilla's root set statically and never reads the OS store (no runtime dependency).","Provide your own rustls ClientConfig with an explicit root store and pass it via `awc::Connector::new().rustls_0_23(Arc::new(config))`, bypassing the native-roots code path entirely.","If you only need plaintext HTTP or manage TLS separately, avoid enabling any native-roots feature so build_tls uses a non-native path.","Verify the image is not distroless/scratch; if it must be, prefer webpki-roots (solution 2) rather than shipping a CA bundle."],"exampleFix":"# before (awc/Cargo.toml or downstream Cargo.toml)\nawc = { version = \"4\", features = [\"rustls-0_23-native-roots\"] }\n\n# after: use bundled webpki roots (no OS cert store required)\nawc = { version = \"4\", features = [\"rustls-0_23-webpki-roots\"] }\n\n# alternative: keep native-roots but fix the Dockerfile (Alpine)\n# RUN apk add --no-cache ca-certificates && update-ca-certificates","handlingStrategy":"fallback","validationCode":"// Run before constructing the awc Connector to detect a missing OS trust store\n// on Linux. native_roots_cert_store reads /etc/ssl/certs (and platform paths).\nuse std::path::Path;\n\nfn os_certs_available() -> bool {\n    // Common Linux locations probed by rustls-native-certs\n    [\"/etc/ssl/certs/ca-certificates.crt\",   // Debian/Ubuntu\n     \"/etc/pki/tls/certs/ca-bundle.crt\",     // RHEL/Fedora\n     \"/etc/ssl/cert.pem\"]                     // Alpine/macOS\n        .iter()\n        .any(|p| {\n            let path = Path::new(p);\n            path.exists() && path.metadata().map(|m| m.len() > 0).unwrap_or(false)\n        })\n}\n\nif !os_certs_available() {\n    panic!(\"no native root certificates; install ca-certificates or use webpki-roots\");\n}","typeGuard":"// No type-level distinction: a feature flag selects native vs webpki roots at\n// compile time, and the panic is runtime. Use a build/runtime check instead.\n// null","tryCatchPattern":"// Connector::new() panics (not returns Err), so isolate it with catch_unwind\n// when you cannot guarantee the OS trust store, then fall back to a manually\n// configured rustls connector:\nuse std::panic;\n\nlet connector = match panic::catch_unwind(|| awc::Connector::new()) {\n    Ok(c) => c,\n    Err(_) => {\n        // Build a rustls config from bundled webpki roots instead\n        use actix_tls::connect::rustls_0_23::webpki_roots_cert_store;\n        use rustls::ClientConfig;\n        let config = ClientConfig::builder()\n            .with_root_certificates(webpki_roots_cert_store())\n            .with_no_client_auth();\n        awc::Connector::new().rustls_0_23(std::sync::Arc::new(config))\n    }\n};\nlet client = awc::Client::builder().connector(connector).finish();","preventionTips":["For containerized deployments prefer the `rustls-0_23-webpki-roots` feature over native-roots to remove the OS dependency entirely.","If you must use native-roots, install `ca-certificates` in your Dockerfile and run update-ca-certificates for Alpine.","Add a startup self-check (see validationCode) that fails fast with a clear message instead of panicking deep in awc.","Keep TLS feature selection in a single, documented place in Cargo.toml so it is reviewable per deployment target.","Smoke-test the client in CI using the same image that runs in production to catch missing trust stores before release."],"tags":["awc","rustls","tls","certificates","docker","panic","startup"],"backgroundTag":null,"analyzedSha":"4d435abc281842f3cbee165b6cde739e001d3a25","analyzedAt":"2026-08-09T01:01:40.926Z","contentChangedAt":"2026-08-09T01:01:40.926Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}