zeroclaw-labs/zeroclaw · error · anyhow::Error

WhatsApp channel send requires Web mode (set session_path, p

Error message

WhatsApp channel send requires Web mode (set session_path, pair_phone, or mode = personal)

What it means

Thrown by build_channel_by_id for whatsapp/whatsapp-web targets when the `whatsapp-web` feature IS compiled in, the `[channels.whatsapp.default]` section exists, but is_web_config() is false. is_web_config() requires a web-mode selector: session_path, pair_phone, pair_code, ws_url, or mode = Personal. A config that only carries Cloud API fields (phone_number_id, access_token, verify_token) — or is essentially empty — fails this check because the send path only supports Web mode.

Source

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

                        .with_workspace_dir(workspace_dir)
                        .with_ack_reactions(ack),
                ))
            }
            #[cfg(not(feature = "channel-matrix"))]
            {
                anyhow::bail!("Matrix channel requires the `channel-matrix` feature");
            }
        }
        "whatsapp" | "whatsapp-web" | "whatsapp_web" => {
            #[cfg(feature = "whatsapp-web")]
            {
                let wa = config
                    .channels
                    .whatsapp
                    .get("default")
                    .context("WhatsApp channel is not configured")?;
                if !wa.is_web_config() {
                    anyhow::bail!(
                        "WhatsApp channel send requires Web mode (set session_path, pair_phone, or mode = personal)"
                    );
                }
                let alias = "default".to_string();
                let peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> = {
                    let cfg_arc = config_arc.clone();
                    let alias = alias.clone();
                    Arc::new(move || cfg_arc.read().channel_external_peers("whatsapp", &alias))
                };
                let allowed_groups_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> = {
                    let cfg_arc = config_arc.clone();
                    let alias = alias.clone();
                    Arc::new(move || {
                        cfg_arc
                            .read()
                            .channels
                            .whatsapp
                            .get(&alias)

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add a web-mode selector to `[channels.whatsapp.default]`: set `session_path`, `pair_phone`, or `mode = "personal"` (pair_code/ws_url also work)
  2. If you meant Cloud API, use the cloud-oriented send/webhook path instead of this one-shot web send
  3. Re-run the send after saving config; the web client defaults a missing session_path once intent is declared

Example fix

# before (zeroclaw.toml)
[channels.whatsapp.default]
phone_number_id = "123"
access_token = "EAAB..."
# error: WhatsApp channel send requires Web mode

# after
[channels.whatsapp.default]
mode = "personal"
session_path = "~/.local/share/zeroclaw/whatsapp-session"
Defensive patterns

Strategy: validation

Validate before calling

// Before a whatsapp web send, assert web-mode intent on the default alias:
let wa = config.channels.whatsapp.get("default").context("whatsapp not configured")?;
if !wa.is_web_config() {
    anyhow::bail!("configure session_path / pair_phone / mode=personal for whatsapp web send");
}

Type guard

fn is_whatsapp_web_ready(cfg: &zeroclaw_config::schema::WhatsAppChannelConfig) -> bool {
    cfg.is_web_config() // session_path | pair_phone | pair_code | ws_url | mode == Personal
}

Try / catch

Err(err) if err.to_string().contains("requires Web mode") => {
    // guide operator: set channels.whatsapp.default.mode = "personal" (or session_path), then retry
}

Prevention

When it happens

Trigger: Sending via a `whatsapp.*` target when `[channels.whatsapp.default]` is configured for the Cloud API (phone_number_id/access_token/verify_token set, no web selectors), or the section exists but none of session_path/pair_phone/pair_code/ws_url/mode=Personal are set. Note this arm always reads alias "default" — other aliases are not consulted here.

Common situations: Config written for WhatsApp Cloud API then used with a send path that only supports Web mode; partial web config (e.g. intended to set session_path but left it out); mode left at its Business default where Personal was meant; copy-pasted example config without the web fields.

Related errors


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