{"record":{"id":"7265bd312d8e06c5","repo":"zeroclaw-labs/zeroclaw","slug":"unsupported-heartbeat-target-channel-channel","errorCode":null,"errorMessage":"unsupported heartbeat.target channel: {channel}","messagePattern":"unsupported heartbeat\\.target channel: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/daemon/mod.rs","lineNumber":2436,"sourceCode":"    }\n    if !config.channels.discord.is_empty() {\n        // Discord requires explicit target — can't auto-detect\n        return None;\n    }\n    if !config.channels.slack.is_empty() {\n        // Slack requires explicit target\n        return None;\n    }\n    if !config.channels.mattermost.is_empty() {\n        // Mattermost requires explicit target\n        return None;\n    }\n    None\n}\n\nfn validate_heartbeat_channel_config(config: &Config, channel: &str) -> Result<()> {\n    if !config.channels.is_known_channel(channel) {\n        anyhow::bail!(\"unsupported heartbeat.target channel: {channel}\");\n    }\n    if !config.channels.is_channel_configured(channel) {\n        anyhow::bail!(\n            \"heartbeat.target is set to {channel} but channels.{channel} is not configured\"\n        );\n    }\n    if !config.channels.is_channel_deliverable(channel) {\n        anyhow::bail!(\n            \"heartbeat.target is set to {channel} but {channel} is an input-only channel that cannot deliver outbound messages\"\n        );\n    }\n    Ok(())\n}\n\nfn has_supervised_channels(config: &Config) -> bool {\n    config.channels.has_any_enabled()\n}\n","sourceCodeStart":2418,"sourceCodeEnd":2454,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/daemon/mod.rs#L2418-L2454","documentation":"validate_heartbeat_channel_config checks heartbeat.target against the channel registry via config.channels.is_known_channel (case-insensitive). The registry covers telegram, discord, slack, mattermost, webhook, imessage, matrix, signal, whatsapp, linq, nextcloud_talk, email, gmail_push, irc, twitch, lark, line, dingtalk, wecom, wecom_ws, wechat, qq, twitter, mochat, nostr, clawdtalk, reddit, bluesky, git, voice_call, voice_wake, voice_duplex, mqtt, amqp, and filesystem; anything else is rejected before delivery is attempted.","triggerScenarios":"heartbeat.target = \"telgram\" (typo); using a provider label like \"openai\" as a channel name; referencing a channel kind not present in this build's registry.","commonSituations":"Typos in channel names; assuming a plugin/add-on channel is registered; confusing model provider names with channel names.","solutions":["Fix the channel name spelling — matching is case-insensitive, so telegram, Telegram, and TELEGRAM all pass","Pick a channel that exists in the registry (telegram, discord, slack, matrix, email, webhook, ...)"],"exampleFix":"# before\n[heartbeat]\nenabled = true\nagent = \"main\"\ntarget = \"telgram\"\nto = \"123456789\"\n\n# after\n[heartbeat]\nenabled = true\nagent = \"main\"\ntarget = \"telegram\"\nto = \"123456789\"","handlingStrategy":"type-guard","validationCode":"if let Some(channel) = &config.heartbeat.target {\n    if !config.channels.is_known_channel(channel) {\n        anyhow::bail!(\"unsupported heartbeat.target channel: {channel}\");\n    }\n}","typeGuard":"fn is_known_heartbeat_channel(config: &zeroclaw_config::schema::Config, channel: &str) -> bool {\n    config.channels.is_known_channel(channel)\n}","tryCatchPattern":"if let Err(err) = run_heartbeat_worker(config.clone()).await {\n    if err.to_string().contains(\"unsupported heartbeat.target channel\") {\n        eprintln!(\"config error: heartbeat.target names a channel not in the registry (typo?)\");\n    }\n    return Err(err);\n}","preventionTips":["Copy channel names from the registry (telegram, discord, slack, matrix, email, ...) rather than typing from memory","Channel matching is case-insensitive — but the name itself must exist in the registry"],"tags":["heartbeat","channels","config-validation"],"backgroundTag":"config-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}