zeroclaw-labs/zeroclaw · error

Webhook channel requires the `channel-webhook` feature

Error message

Webhook channel requires the `channel-webhook` feature

What it means

deliver_announcement bails when the channel is "webhook.<alias>" and the binary lacks the `channel-webhook` cargo feature: the webhook arm is compiled out and the cfg(not(...)) stub reports it. webhook is part of default-channels, so this occurs only on builds that disabled defaults or chose an explicit subset. The webhook arm is also the generic escape hatch for push delivery, so losing it disables a common fallback route.

Source

Thrown at crates/zeroclaw-channels/src/orchestrator/mod.rs:12996

                .get(alias)
                .ok_or_else(not_configured)?;
            let ch = WebhookChannel::new(
                alias.to_string(),
                wh.port,
                wh.listen_path.clone(),
                wh.send_url.clone(),
                wh.send_method.clone(),
                wh.auth_header.clone(),
                wh.secret.clone(),
                wh.max_retries,
                wh.retry_base_delay_ms,
                wh.retry_max_delay_ms,
            );
            zeroclaw_api::channel::Channel::send(&ch, &make_msg(&safe_output)).await?;
        }
        #[cfg(not(feature = "channel-webhook"))]
        "webhook" => {
            anyhow::bail!("Webhook channel requires the `channel-webhook` feature");
        }
        "wecom_ws" | "wecom-ws" => {
            let _ = config
                .channels
                .wecom_ws
                .get(alias)
                .ok_or_else(not_configured)?;
            anyhow::bail!("wecom_ws channel is not connected");
        }
        #[cfg(feature = "channel-email")]
        "email" => {
            let em = config
                .channels
                .email
                .get(alias)
                .ok_or_else(not_configured)?;
            let peers = config.channel_external_peers("email", alias);
            let peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> =

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Rebuild with cargo build --features zeroclaw-channels/channel-webhook (or restore default-channels)
  2. Use a default build, which already includes webhook
  3. Or retarget the cron to another compiled-in channel

Example fix

# before
cargo build --no-default-features --features zeroclaw-channels/channel-telegram
# cron channel = "webhook.ops" -> bail: requires `channel-webhook`

# after
cargo build --no-default-features --features "zeroclaw-channels/channel-telegram,zeroclaw-channels/channel-webhook"
Defensive patterns

Strategy: validation

Validate before calling

fn webhook_delivery_compiled() -> bool {
    cfg!(feature = "channel-webhook")
}

for cron in &config.crons_where(|c| c.channel.starts_with("webhook.")) {
    if !webhook_delivery_compiled() {
        anyhow::bail!("cron {} targets webhook but channel-webhook is not compiled in", cron.id);
    }
}

Try / catch

match deliver_announcement(&cfg, "webhook.ops", &target, thread, &out).await {
    Err(e) if e.to_string().contains("requires the `channel-webhook` feature") => {
        // Build-time defect: disable the cron and alert; no retry path.
    }
    rest => rest?,
}

Prevention

When it happens

Trigger: Calling deliver_announcement with channel = "webhook.<alias>" on a build compiled with default-features = false and no channel-webhook; a webhook cron firing on such a binary.

Common situations: Minimal downstream builds trimming every optional channel; test builds with only one specific channel feature enabled.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/f50f19bca430a783. Report an issue: GitHub.