Error message
invalid peer certificate: UnknownIssuer
Also printed as
- InvalidCertificate(UnknownIssuer)
reqwest prints it at the end of its source chain: "error sending request for url (…): client error (Connect): invalid peer certificate: UnknownIssuer"; Debug output shows InvalidCertificate(UnknownIssuer). ureq prints "io: invalid peer certificate: UnknownIssuer". Native binaries built on rustls (pnpm 12, many CLIs) show the same text.
rustls (via reqwest, ureq, hyper-rustls, tonic) — rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer)
What it means
rustls could not chain the server's certificate to any trust anchor it was configured with. UnknownIssuer is rustls's single code for every path-building failure: a private or proxy CA, a missing intermediate, or a self-signed certificate. Which roots count as trusted depends on how the crate was built: the platform verifier (OS store), rustls-native-certs (OS roots loaded at start-up) or webpki-roots (Mozilla's list compiled in).
Why it happens
A company or private CA
commonThe server's chain ends at a root that is not among the configured anchors, typical for internal services and TLS-inspecting proxies.
The client trusts only compiled-in public roots
commonCrates built with webpki-roots ignore the OS store completely, so a root installed by IT never applies. reqwest 0.13's default platform verifier does use the OS store (as the reproduction confirmed after update-ca-certificates).
The server omits its intermediate
occasionalrustls does not fetch missing intermediates; a leaf-only server fails with UnknownIssuer even if the root is trusted.
A self-signed server certificate
occasionalrustls reports self-signed certificates as UnknownIssuer too; trust the certificate as a root for that client, or replace it.
How to fix it
- 1.
Add the root to the client
ClientBuilder::add_root_certificate adds an anchor while keeping full verification (names, dates).
rust // Trust a private root for this client (in addition to the default roots) let pem = std::fs::read("corp-root-ca.pem")?; let client = reqwest::Client::builder() .add_root_certificate(reqwest::Certificate::from_pem(&pem)?) .build()?; - 2.
Install the root in the OS store
With the platform verifier (reqwest 0.13 default), roots in the operating system's store are trusted; on Linux, update-ca-certificates is enough.
bash # reqwest 0.13 verifies with the platform verifier: install the root in the OS store sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates - 3.
Check which root source is compiled in
cargo tree shows whether webpki-roots or rustls-native-certs is used; switch features if the OS store must apply.
bash # Which root source is compiled into this binary? (a crate that is absent reports no match) cargo tree -e features -i rustls-platform-verifier # OS verifier (reqwest 0.13 default) cargo tree -e features -i rustls-native-certs # OS roots loaded at start-up cargo tree -e features -i webpki-roots # Mozilla roots compiled in, OS store ignored - 4.
Server owners: send the intermediate
A single certificate in the handshake whose issuer is an intermediate means the server configuration is incomplete.
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:'
Related errors
invalid peer certificate: certificate expired: verification timerustls 0.23 (via reqwest, ureq, hyper-rustls)invalid peer certificate: certificate not valid for name "api.example.com"; cer…rustls 0.23 (via reqwest, ureq, hyper-rustls)Error: ERR_PNPM_RESOLVING_NPM_RESOLVER_NETWORK_ERRORpnpm 12 (native binary, rustls)x509: certificate signed by unknown authorityGo crypto/x509