{"record":{"id":"4f70b6268a16ca78","repo":"zeroclaw-labs/zeroclaw","slug":"failed-to-build-webhook-http-client","errorCode":null,"errorMessage":"failed to build webhook HTTP client","messagePattern":"failed to build webhook HTTP client","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/hooks/builtin/webhook_audit.rs","lineNumber":139,"sourceCode":"        if !config.url.is_empty()\n            && let Err(e) = validate_webhook_url(&config.url)\n        {\n            ::zeroclaw_log::record!(\n                ERROR,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                    .with_attrs(\n                        ::serde_json::json!({\"hook\": \"webhook-audit\", \"error\": format!(\"{}\", e)})\n                    ),\n                \"webhook URL validation failed\"\n            );\n            panic!(\"webhook-audit: {e}\");\n        }\n\n        let client = reqwest::Client::builder()\n            .timeout(Duration::from_secs(5))\n            .build()\n            .expect(\"failed to build webhook HTTP client\");\n        Self {\n            config,\n            client,\n            pending_args: Arc::new(Mutex::new(HashMap::new())),\n        }\n    }\n}\n\n/// Simple glob matching: `*` matches any sequence of characters.\nfn glob_matches(pattern: &str, text: &str) -> bool {\n    if pattern == \"*\" {\n        return true;\n    }\n    if !pattern.contains('*') {\n        return pattern == text;\n    }\n\n    let parts: Vec<&str> = pattern.split('*').collect();","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/hooks/builtin/webhook_audit.rs#L121-L157","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (Cargo.toml): mixed TLS features\nreqwest = { version = \"0.12\", features = [\"default-tls\"] }\n\n// after: one rustls-based stack, no runtime OpenSSL\nreqwest = { version = \"0.12\", default-features = false, features = [\"rustls-tls\", \"json\"] }","handlingStrategy":"fallback","validationCode":"// Deploy-time smoke test: fail the deploy, not the runtime panic.\nfn tls_ok() -> bool {\n    std::panic::catch_unwind(|| {\n        reqwest::Client::builder().timeout(std::time::Duration::from_secs(5)).build().is_ok()\n    }).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"// If native TLS init is broken, fall back to an explicit rustls client:\nlet client = match reqwest::Client::builder().timeout(Duration::from_secs(5)).build() {\n    Ok(c) => c,\n    Err(e) => {\n        tracing::warn!(\"default TLS init failed ({e}); retrying with rustls\");\n        reqwest::Client::builder()\n            .timeout(Duration::from_secs(5))\n            .use_rustls_tls()\n            .build()?\n    }\n};","preventionTips":["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."],"tags":["rust","reqwest","http-client","tls","docker","webhook"],"backgroundTag":"reqwest-client-build-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}