{"record":{"id":"ca0813a5a35b79eb","repo":"zeroclaw-labs/zeroclaw","slug":"unknown-channel-channel-id-supported-telegra","errorCode":null,"errorMessage":"Unknown channel '{channel_id}'. Supported: telegram, discord, slack, mattermost, signal, matrix, whatsapp, qq, lark, feishu, dingtalk, wecom, wecom_ws, nextcloud_talk, linq, email, gmail_push, git, irc, twitter, mochat, imessage, line, voice-call","messagePattern":"Unknown channel '(.+?)'\\. Supported: telegram, discord, slack, mattermost, signal, matrix, whatsapp, qq, lark, feishu, dingtalk, wecom, wecom_ws, nextcloud_talk, linq, email, gmail_push, git, irc, twitter, mochat, imessage, line, voice-call","errorType":"exception","errorClass":"UnknownChannelId","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/orchestrator/mod.rs","lineNumber":9674,"sourceCode":"            }\n        }\n        \"voice-call\" => {\n            #[cfg(feature = \"channel-voice-call\")]\n            {\n                let (alias, vc) = config\n                    .channels\n                    .voice_call\n                    .iter()\n                    .next()\n                    .context(\"Voice Call channel is not configured\")?;\n                Ok(Arc::new(VoiceCallChannel::new(alias.clone(), vc.clone())))\n            }\n            #[cfg(not(feature = \"channel-voice-call\"))]\n            {\n                anyhow::bail!(\"Voice Call channel requires the `channel-voice-call` feature\");\n            }\n        }\n        other => Err(anyhow::Error::new(UnknownChannelId(other.to_string()))),\n    }\n}\n\n/// Send a one-off message to a configured channel.\npub async fn send_channel_message(\n    config: &Config,\n    channel_id: &str,\n    recipient: &str,\n    message: &str,\n) -> Result<()> {\n    // Wrap into the canonical shared handle for the builder; this is a\n    // one-shot path so the snapshot is dropped immediately after send.\n    let config_arc = Arc::new(RwLock::new(config.clone()));\n    // The builder gets first refusal so families it already resolves natively\n    // (notably `linq.<alias>`) keep their established route and their own\n    // configuration errors. Only a dotted id the builder does not claim at all\n    // falls through to the announcement dispatcher, which resolves any\n    // `<type>.<alias>` it supports.","sourceCodeStart":9656,"sourceCodeEnd":9692,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/orchestrator/mod.rs#L9656-L9692","documentation":"The channel orchestrator maps a channel id string to its builder via a match over the supported set. Any id outside the vocabulary (telegram, discord, slack, mattermost, signal, matrix, whatsapp, qq, lark, feishu, dingtalk, wecom, wecom_ws, nextcloud_talk, linq, email, gmail_push, git, irc, twitter, mochat, imessage, line, voice-call) is wrapped in UnknownChannelId. Feature-gated channels also produce a distinct bail! when compiled without their feature.","triggerScenarios":"Calling the orchestrator's channel construction with a misspelled or unsupported id: 'telgram', 'WebChat', a display name instead of the id, or 'voice-call' in a binary built without the channel-voice-call feature (that path bails separately with the feature message).","commonSituations":"Typos in channel config files, configs written against a newer ZeroClaw release with new channels then run on an older binary, whitespace/casing drift from YAML, channels whose cargo feature was not enabled at build time.","solutions":["Use one of the listed ids exactly (lowercase, underscores where shown), after trimming whitespace from config values.","For voice-call, rebuild/install a binary compiled with the channel-voice-call feature; the feature-gated branch tells you when it is missing.","Diff the config's channel ids against the supported list in the error message at startup and fail fast before any messaging happens.","If the channel exists upstream but not in your binary, upgrade to a release that includes it."],"exampleFix":"# before\nchannels:\n  telgram:\n    token: ...\n\n# after\nchannels:\n  telegram:\n    token: ...","handlingStrategy":"type-guard","validationCode":"const SUPPORTED_CHANNELS: &[&str] = &[\"telegram\",\"discord\",\"slack\",\"mattermost\",\"signal\",\"matrix\",\"whatsapp\",\"qq\",\"lark\",\"feishu\",\"dingtalk\",\"wecom\",\"wecom_ws\",\"nextcloud_talk\",\"linq\",\"email\",\"gmail_push\",\"git\",\"irc\",\"twitter\",\"mochat\",\"imessage\",\"line\",\"voice-call\"];\n\nfn assert_supported(channel_id: &str) -> anyhow::Result<()> {\n    anyhow::ensure!(SUPPORTED_CHANNELS.contains(&channel_id.trim()), \"unsupported channel id {channel_id}\");\n    Ok(())\n}","typeGuard":"fn is_supported_channel(channel_id: &str) -> bool {\n    SUPPORTED_CHANNELS.contains(&channel_id.trim())\n}","tryCatchPattern":"match orchestrator::build_channel(config, channel_id).await {\n    Err(e) if e.downcast_ref::<UnknownChannelId>().is_some() => {\n        fail_fast_with_supported_list(); // config error: stop startup, list valid ids\n    }\n    other => other,\n}","preventionTips":["Validate all channel ids from config against the supported list at startup, before any message flows.","Trim whitespace and normalize casing when loading channel ids from YAML/TOML.","Pin the release notes: when adopting new channels, confirm your binary was built with their cargo features."],"tags":["channels","configuration","orchestrator","unknown-channel"],"backgroundTag":"unknown-channel-id","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}