{"record":{"id":"82f6e2007ceb882c","repo":"zeroclaw-labs/zeroclaw","slug":"unsupported-delivery-mode","errorCode":null,"errorMessage":"unsupported delivery mode: {}","messagePattern":"unsupported delivery mode: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/cron/mod.rs","lineNumber":145,"sourceCode":"        agent_alias,\n        name,\n        schedule,\n        command,\n        delivery,\n        shell_output_format,\n    )\n}\n\npub fn validate_delivery_config(delivery: Option<&DeliveryConfig>) -> Result<()> {\n    let Some(delivery) = delivery else {\n        return Ok(());\n    };\n\n    if delivery.mode.eq_ignore_ascii_case(\"none\") {\n        return Ok(());\n    }\n    if !delivery.mode.eq_ignore_ascii_case(\"announce\") {\n        bail!(\"unsupported delivery mode: {}\", delivery.mode);\n    }\n\n    let channel = delivery.channel.as_deref().map(str::trim);\n    if channel.filter(|value| !value.is_empty()).is_none() {\n        bail!(\"delivery.channel is required for announce mode\");\n    }\n\n    let has_target = delivery\n        .to\n        .as_deref()\n        .map(str::trim)\n        .is_some_and(|value| !value.is_empty());\n    if !has_target {\n        bail!(\"delivery.to is required for announce mode\");\n    }\n\n    Ok(())\n}","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/cron/mod.rs#L127-L163","documentation":"validate_delivery_config whitelists cron delivery modes: 'none' (case-insensitive) returns Ok immediately; 'announce' proceeds to require a channel; every other mode string bails. Webhook delivery is NOT a mode — webhook targets are configured under announce mode (validate_delivery_accepts_webhook_with_thread_id pins this), which is why mode='webhook' is rejected.","triggerScenarios":"add_shell_job / add_agent_job / cron handle_command invoked with delivery.mode set to 'webhook', 'send', 'message', 'email', or a typo like 'anounce'. Case variants such as 'Announce' pass; any other token does not.","commonSituations":"Users assuming webhook is a first-class delivery mode; configs copied from other tools with different vocabularies; config drift across versions where docs/examples disagreed.","solutions":["Set delivery.mode to 'announce' (and provide delivery.channel) or 'none'","For webhook delivery, keep mode 'announce' and configure the webhook target/thread id in the delivery target fields","Check the cron config schema/docs for accepted mode and target fields","Normalize the mode string (trim, lowercase) before validation if config sources may inject whitespace or casing"],"exampleFix":"// before\ndelivery = { mode: \"webhook\", channel: None }\n\n// after\ndelivery = { mode: \"announce\", channel: Some(\"telegram:ops\".into()), to: Some(target) }","handlingStrategy":"validation","validationCode":"if !delivery_is_valid(&delivery) {\n    anyhow::bail!(\"delivery.mode must be 'none' or 'announce' (webhooks are configured as announce targets)\");\n}\ncron.add_shell_job(spec, delivery).await?;","typeGuard":"fn is_supported_delivery_mode(mode: &str) -> bool {\n    matches!(mode.trim().to_ascii_lowercase().as_str(), \"none\" | \"announce\")\n}","tryCatchPattern":null,"preventionTips":["Remember the vocabulary: modes are none/announce; webhooks are targets under announce","Validate delivery blocks at config load, not only at job creation","Normalize mode strings (trim + lowercase) before submission","Pin the accepted modes in your config schema/docs"],"tags":["cron","delivery-config","enum-validation","config"],"backgroundTag":"config-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}