getzola/zola · critical

reqwest client build

Error message

reqwest client build

What it means

The link_checker component builds a shared reqwest::blocking::Client once (LazyLock) so connections are reused, and panics via .expect("reqwest client build") if the client cannot be constructed. reqwest fails Client::builder().build() only when the TLS backend cannot be initialized.

Source

Thrown at components/link_checker/src/lib.rs:38

    }
}

pub fn message(res: &Result) -> String {
    match res {
        Ok(code) => code.to_string(),
        Err(error) => error.clone(),
    }
}

// Keep history of link checks so a rebuild doesn't have to check again
static LINKS: LazyLock<Arc<RwLock<HashMap<String, Result>>>> =
    LazyLock::new(|| Arc::new(RwLock::new(HashMap::new())));
// Make sure to create only a single Client so that we can reuse the connections
static CLIENT: LazyLock<Client> = LazyLock::new(|| {
    Client::builder()
        .user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")))
        .build()
        .expect("reqwest client build")
});

pub fn check_url(url: &str, config: &LinkChecker) -> Result {
    {
        let guard = LINKS.read().unwrap();
        if let Some(res) = guard.get(url) {
            return res.clone();
        }
    }

    let mut headers = HeaderMap::new();
    headers.insert(ACCEPT, "text/html".parse().unwrap());
    headers.append(ACCEPT, "*/*".parse().unwrap());

    // TODO: pass the client to the check_url, do not pass the config

    let check_anchor = !config.skip_anchor_prefixes.iter().any(|prefix| url.starts_with(prefix));

View on GitHub (pinned to 61d3082821)

Solutions

  1. Install the TLS runtime prerequisites on the target machine (e.g. libssl, ca-certificates packages).
  2. Build reqwest with the rustls-tls feature to avoid native OpenSSL dependence.
  3. Rebuild/reinstall the binary for the target platform with matching TLS features.
  4. Verify with a minimal reqwest build/run on the same host to isolate the TLS init failure.

Example fix

// before (Cargo.toml)
reqwest = { version = "0.12", features = ["blocking"] }
// after
reqwest = { version = "0.12", features = ["blocking", "rustls-tls"], default-features = false }
Defensive patterns

Strategy: fallback

Validate before calling

// Check TLS prerequisites before first network call
std::process::Command::new("ldconfig").args(["-p"]).output()
    .map(|o| String::from_utf8_lossy(&o.stdout).contains("libssl"))
    .unwrap_or(false); // also verify /etc/ssl/certs exists

Prevention

When it happens

Trigger: First call to check_url (which triggers the CLIENT LazyLock) when reqwest's TLS backend fails to initialize — typically missing/broken native TLS or OpenSSL setup, or a mismatched feature set (rustls vs native-tls) at build time.

Common situations: Deploying to a slim Docker image without OpenSSL/ca-certificates; cross-compiling with an incompatible TLS feature; a distro whose OpenSSL version is incompatible with the compiled crate.

Related errors


AI-assisted analysis of getzola/zola@61d3082821 (2026-09-03). Data as JSON: /api/errors/9ba13b6f74ae4b9b. Report an issue: GitHub.