xai-org/grok-build · critical
failed to build shared blocking HTTP client
Error message
failed to build shared blocking HTTP client
What it means
This panic fires when `reqwest::blocking::Client::build()` fails inside `shared_startup_blocking_client`, the lazy initializer for a process-wide blocking HTTP client used at startup. The builder itself validates configuration (TLS backend, timeout values, user-agent), so a failure here means the client could not be constructed at all — typically an TLS/runtime initialization problem, not a network issue. The `.expect` deliberately aborts startup because no HTTP fetches can proceed without this client.
Source
Thrown at crates/codegen/xai-grok-http/src/lib.rs:579
///
/// Mirrors `shared_client()`'s pool self-healing for the same reason: this client is reused (settings, prefetch).
/// Idle and TCP eviction drops a connection before the upstream idle window (~60-100s; 30s is a conservative default) closes it.
/// The HTTP/2 keepalive-ping setters that `shared_client()` uses are not exposed on reqwest's blocking `ClientBuilder` (0.12).
/// Only the idle and TCP eviction half applies here.
pub fn shared_startup_blocking_client() -> reqwest::blocking::Client {
static BLOCKING_CLIENT: OnceLock<reqwest::blocking::Client> = OnceLock::new();
BLOCKING_CLIENT
.get_or_init(|| {
let _timer = startup_timer!("startup.http_blocking_client_build");
xai_grok_extra_ca::build_blocking_reqwest_client(|builder| {
builder
.connect_timeout(STARTUP_FETCH_TIMEOUT)
.timeout(STARTUP_FETCH_TIMEOUT)
.user_agent(process_user_agent_string())
.pool_idle_timeout(std::time::Duration::from_secs(30))
.tcp_keepalive(std::time::Duration::from_secs(30))
})
.expect("failed to build shared blocking HTTP client")
})
.clone()
}
#[allow(clippy::disallowed_methods)] // test clients hit localhost mocks
#[cfg(test)]
mod tests {
use super::*;
/// `error_cause_chain` appends each `source()` joined with ": ", so a reqwest error whose `Display` hides the hyper cause still surfaces it.
#[test]
fn error_cause_chain_appends_hidden_sources() {
#[derive(Debug)]
struct Leaf;
impl std::fmt::Display for Leaf {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "connection closed before message completed")
}View on GitHub (pinned to bc7f02eddd)
Solutions
- Check the panic's inner source message from reqwest — it names the exact build failure (usually TLS backend or root-store load).
- On Linux, ensure the CA bundle exists (ca-certificates installed) or set SSL_CERT_FILE to a valid PEM bundle.
- If the failure is TLS-root related, try a build with a vendored root store (rustls-tls with webpki-roots) or embed certs.
- Verify the binary runs on a supported platform where tokio's blocking runtime can spawn threads (ulimit/thread limits can starve client construction).
Example fix
// before
.expect("failed to build shared blocking HTTP client")
// after
.map_err(|e| StartupError::HttpClientInit(e.to_string()))? // or log and fall back to a per-request client Defensive patterns
Strategy: fallback
Validate before calling
// preflight: ensure a CA bundle is visible before building the client
if std::env::var_os("SSL_CERT_FILE").map_or(true, |p| !std::path::Path::new(&p).exists()) {
eprintln!("warning: SSL_CERT_FILE missing; client build may fail");
} Try / catch
// Rust: catch_unwind around lazy init, or make the initializer fallible
let client = std::panic::catch_unwind(shared_startup_blocking_client)
.map_err(|_| StartupError::HttpClientInit)?; Prevention
- Ship a vendored root store (rustls + webpki-roots) so builds don't depend on host CA state
- Log the inner reqwest builder error, not just the expect message
- Smoke-test the binary in minimal containers where cert stores are often absent
When it happens
Trigger: Calling any startup fetch path that lazily initializes the shared client when reqwest's ClientBuilder rejects the configuration — e.g. native-tls/rustls backend initialization failure, invalid timeout resolution, or TLS root store load failure on the host.
Common situations: Hosts with a broken or missing system certificate store; statically-linked binaries whose TLS backend cannot load roots; exotic platforms where reqwest's blocking runtime (tokio) cannot be initialized; invalid env-var-driven TLS configuration (e.g. bad SSL_CERT_FILE).
Related errors
- Task panicked: {}
- Failed to load config: {e}
- default reqwest client builds
- aws-lc-rs supports the default protocol versions
- failed to build shared HTTP client
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/76b60041006d4727.
Report an issue: GitHub.