zeroclaw-labs/zeroclaw · error
failed to build webhook HTTP client
Error message
failed to build webhook HTTP client
What it means
WebhookAudit::new() constructs a reqwest::Client with a 5-second timeout and expects success. Client::builder().build() fails essentially only when the TLS backend cannot initialize (missing/incompatible OpenSSL for native-tls, conflicting rustls/native-tls feature selection, or a corrupt CA store), so this panic means the webhook-audit hook could not get a usable HTTP client.
Source
Thrown at crates/zeroclaw-runtime/src/hooks/builtin/webhook_audit.rs:139
if !config.url.is_empty()
&& let Err(e) = validate_webhook_url(&config.url)
{
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(
::serde_json::json!({"hook": "webhook-audit", "error": format!("{}", e)})
),
"webhook URL validation failed"
);
panic!("webhook-audit: {e}");
}
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.build()
.expect("failed to build webhook HTTP client");
Self {
config,
client,
pending_args: Arc::new(Mutex::new(HashMap::new())),
}
}
}
/// Simple glob matching: `*` matches any sequence of characters.
fn glob_matches(pattern: &str, text: &str) -> bool {
if pattern == "*" {
return true;
}
if !pattern.contains('*') {
return pattern == text;
}
let parts: Vec<&str> = pattern.split('*').collect();View on GitHub (pinned to 88bb9c8533)
Solutions
- Install CA certificates in the image (apk add ca-certificates / apt-get install ca-certificates) if using native-tls.
- Unify the reqwest TLS feature across the workspace (prefer rustls-tls) so no runtime OpenSSL is required.
- Check dynamic linkage (ldd on the binary) for a missing or wrong-version libssl/libcrypto.
- If hook construction must not abort startup, gate webhook-audit behind a health check at deploy time.
Example fix
// before (Cargo.toml): mixed TLS features
reqwest = { version = "0.12", features = ["default-tls"] }
// after: one rustls-based stack, no runtime OpenSSL
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] } Defensive patterns
Strategy: fallback
Validate before calling
// Deploy-time smoke test: fail the deploy, not the runtime panic.
fn tls_ok() -> bool {
std::panic::catch_unwind(|| {
reqwest::Client::builder().timeout(std::time::Duration::from_secs(5)).build().is_ok()
}).unwrap_or(false)
} Try / catch
// If native TLS init is broken, fall back to an explicit rustls client:
let client = match reqwest::Client::builder().timeout(Duration::from_secs(5)).build() {
Ok(c) => c,
Err(e) => {
tracing::warn!("default TLS init failed ({e}); retrying with rustls");
reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.use_rustls_tls()
.build()?
}
}; Prevention
- Standardize the whole workspace on one reqwest TLS feature (rustls-tls) to avoid runtime OpenSSL.
- Install ca-certificates in minimal container images.
- Smoke-test HTTP client construction in the target container image during CI/deploy.
When it happens
Trigger: Instantiating the webhook-audit hook in an environment where the process's TLS stack fails to init: alpine/distroless images with native-tls but no ca-certificates, two crates forcing different reqwest TLS features, or an OS OpenSSL library with a broken version match.
Common situations: Deploying the agent into slim Docker images; adding a dependency that flips reqwest from rustls-tls to default-tls; glibc/OpenSSL mismatches after a base-image upgrade.
Related errors
- HTTP client build
- failed to build reqwest client
- failed to build HTTP client
- amqp channel '{}': client_cert is set but client_key is miss
- amqp channel '{}': client_key is set but client_cert is miss
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/4f70b6268a16ca78.
Report an issue: GitHub.