block/buzz · critical

push HTTP client

Error message

push HTTP client

What it means

run_delivery_worker builds one reqwest::Client (with push_gateway_timeout) for all push-gateway deliveries. Client::build() almost never fails; the realistic failure is TLS-backend initialization (e.g. native-tls/OpenSSL context creation) failing in the process environment. The expect panics, so the push delivery worker task dies at startup and no pushes are ever delivered.

Source

Thrown at crates/buzz-relay/src/push_runtime.rs:316

        return true;
    }
    let p = nostr::SingleLetterTag::lowercase(nostr::Alphabet::P);
    filter.generic_tags.get(&p).is_some_and(|values| {
        !values.is_empty()
            && values.iter().all(|value| value == lease_author_hex)
            && event
                .tags
                .filter(nostr::TagKind::SingleLetter(p))
                .any(|tag| tag.content() == Some(lease_author_hex))
    })
}

/// Continuously claim due wakes and deliver them through the push gateway.
pub async fn run_delivery_worker(state: Arc<AppState>) {
    let http = reqwest::Client::builder()
        .timeout(state.config.push_gateway_timeout)
        .build()
        .expect("push HTTP client");
    let mut idle_delay = Duration::from_millis(500);
    loop {
        let mut found = false;
        match state.db.usage_community_hosts().await {
            Ok(communities) => {
                for community in communities {
                    let community = buzz_core::CommunityId::from_uuid(community.id);
                    let until = Utc::now() + TimeDelta::seconds(CLAIM_SECS);
                    match state.db.claim_due_push_wakes(community, 16, until).await {
                        Ok(wakes) => {
                            for wake in wakes {
                                found = true;
                                deliver_one(&state, &http, wake).await;
                            }
                        }
                        Err(e) => warn!(%community, "push wake claim failed: {e}"),
                    }
                }

View on GitHub (pinned to 934f3325c3)

Solutions

  1. Build reqwest with the rustls TLS backend (features = ["rustls-tls"]) so no system OpenSSL is needed — consistent with the ring provider the relay already installs
  2. Verify the TLS libraries the binary links (ldd) exist and match inside the runtime image
  3. Propagate the build error instead of expect so a dead push worker surfaces as an observable startup failure

Example fix

// before
let http = reqwest::Client::builder()
    .timeout(state.config.push_gateway_timeout)
    .build()
    .expect("push HTTP client");

// after
let http = reqwest::Client::builder()
    .timeout(state.config.push_gateway_timeout)
    .build()
    .map_err(|e| {
        tracing::error!("push worker: HTTP client build failed: {e}");
        e
    })?; // make run_delivery_worker return Result and report at spawn site
Defensive patterns

Strategy: validation

Validate before calling

// startup preflight before spawning the push worker
let probe = reqwest::Client::builder().build();
if probe.is_err() {
    return Err(anyhow!("push worker: reqwest client cannot initialize (TLS backend problem)"));
}

Prevention

When it happens

Trigger: reqwest compiled with native-tls on a host where OpenSSL fails to initialize (missing or incompatible shared libraries); minimal container images lacking the TLS backend's runtime prerequisites.

Common situations: Distroless/alpine images without a compatible OpenSSL; host OpenSSL upgrades after the binary was built; CI runners with restrictive syscall filters.

Related errors


AI-assisted analysis of block/buzz@934f3325c3 (2026-08-20). Data as JSON: /api/errors/929eac651313331b. Report an issue: GitHub.