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

delivery.channel is required for announce mode

Error message

delivery.channel is required for announce mode

What it means

After the mode whitelist passes, announce mode must name a channel: delivery.channel must be present and non-empty after trimming. Missing, empty, or whitespace-only channel bails before target validation. A delivery.to target alone is not sufficient — the channel is required for announce.

Source

Thrown at crates/zeroclaw-runtime/src/cron/mod.rs:150

        shell_output_format,
    )
}

pub fn validate_delivery_config(delivery: Option<&DeliveryConfig>) -> Result<()> {
    let Some(delivery) = delivery else {
        return Ok(());
    };

    if delivery.mode.eq_ignore_ascii_case("none") {
        return Ok(());
    }
    if !delivery.mode.eq_ignore_ascii_case("announce") {
        bail!("unsupported delivery mode: {}", delivery.mode);
    }

    let channel = delivery.channel.as_deref().map(str::trim);
    if channel.filter(|value| !value.is_empty()).is_none() {
        bail!("delivery.channel is required for announce mode");
    }

    let has_target = delivery
        .to
        .as_deref()
        .map(str::trim)
        .is_some_and(|value| !value.is_empty());
    if !has_target {
        bail!("delivery.to is required for announce mode");
    }

    Ok(())
}

pub fn add_shell_job_with_approval(
    config: &Config,
    agent_alias: &str,
    name: Option<String>,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set delivery.channel to a configured, non-empty channel identifier
  2. Trim channel values if config sources may carry whitespace
  3. If no announcement is wanted, use mode 'none' instead of announce-without-channel
  4. Validate the whole delivery block in config loading, not just at job creation

Example fix

// before
delivery = { mode: "announce", channel: None, to: Some("@ops") }

// after
delivery = { mode: "announce", channel: Some("telegram:ops".into()), to: Some("@ops") }
Defensive patterns

Strategy: validation

Validate before calling

if !delivery_is_valid(&delivery) {
    anyhow::bail!("announce mode requires a non-empty delivery.channel");
}
cron.add_agent_job(spec, delivery).await?;

Type guard

fn delivery_is_valid(d: &DeliveryConfig) -> bool {
    if d.mode.eq_ignore_ascii_case("none") { return true; }
    if !d.mode.eq_ignore_ascii_case("announce") { return false; }
    d.channel.as_deref().map(|c| !c.trim().is_empty()).unwrap_or(false)
}

Prevention

When it happens

Trigger: delivery = { mode: 'announce' } with channel omitted, set to "", or set to spaces; programmatically built configs that populate only the `to` field.

Common situations: Hand-written cron YAML/TOML forgetting the channel field; templates assuming a default channel; field renames during refactors leaving channel unset.

Related errors


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