{"record":{"id":"730f1d3bf94c68d7","repo":"zeroclaw-labs/zeroclaw","slug":"channels-discord-alias-bot-token-is-unset-but-th","errorCode":null,"errorMessage":"channels.discord.{alias}.bot_token is unset but the channel is enabled — the channel cannot connect until a bot token is set","messagePattern":"channels\\.discord\\.(.+?)\\.bot_token is unset but the channel is enabled — the channel cannot connect until a bot token is set","errorType":"console","errorClass":"DiagItem","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-runtime/src/doctor/mod.rs","lineNumber":1349,"sourceCode":"    }\n\n    // Enabled bot channels with no token: a partial alias survives the\n    // resilient load (`bot_token` has a serde default), so it never\n    // reaches `degraded_sections` — doctor must name the unset field here\n    // or the operator only finds out when the channel fails to start.\n    for (alias, tg) in &cc.telegram {\n        if tg.enabled && zeroclaw_config::traits::is_unset_display_value(&tg.bot_token) {\n            items.push(DiagItem::warn(\n                cat,\n                format!(\n                    \"channels.telegram.{alias}.bot_token is unset but the channel is enabled — the channel cannot connect until a bot token is set\"\n                ),\n            ));\n        }\n    }\n    for (alias, dc) in &cc.discord {\n        if dc.enabled && zeroclaw_config::traits::is_unset_display_value(&dc.bot_token) {\n            items.push(DiagItem::warn(\n                cat,\n                format!(\n                    \"channels.discord.{alias}.bot_token is unset but the channel is enabled — the channel cannot connect until a bot token is set\"\n                ),\n            ));\n        }\n    }\n\n    // Delegate agents: model_provider validity (resolved from model_provider alias)\n    let mut agent_names: Vec<_> = config.agents.keys().collect();\n    agent_names.sort();\n    for name in agent_names {\n        let agent = config.agents.get(name).unwrap();\n        let provider_ref = agent.model_provider.as_str();\n        if provider_ref.is_empty() {\n            continue;\n        }\n        if let Some(reason) = provider_validation_error(config, provider_ref) {","sourceCodeStart":1331,"sourceCodeEnd":1367,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/doctor/mod.rs#L1331-L1367","documentation":"A `zeroclaw doctor` warning from `check_config_semantics`: the Discord twin of the Telegram token check — a Discord alias has `enabled = true` while its `bot_token` is an unset display value. The serde default on `bot_token` means the partial alias loads without entering `degraded_sections`, so doctor names the unset field before the channel fails to connect.","triggerScenarios":"Running `zeroclaw doctor` when `channels.discord.<alias>` sets `enabled = true` but `bot_token` is empty or an unresolved `${...}` placeholder (`zeroclaw_config::traits::is_unset_display_value`).","commonSituations":"Discord bot token from the developer portal never pasted into config; env-var-indirected token missing from the systemd unit or container env; enabling the Discord alias before finishing setup.","solutions":["Set a real token from the Discord developer portal in `channels.discord.<alias>.bot_token`, or export the env var it references where the daemon runs.","For systemd, wire `EnvironmentFile=` into the unit so the placeholder resolves at start.","Set `enabled = false` if the channel should not connect yet.","Re-run `zeroclaw doctor` to confirm the warning cleared."],"exampleFix":"# before\n[channels.discord.default]\nenabled = true\nbot_token = \"\"\n\n# after\n[channels.discord.default]\nenabled = true\nbot_token = \"MTIzNDU2Nzg-your-discord-token\"","handlingStrategy":"validation","validationCode":"for (alias, dc) in &config.channels.discord {\n    if dc.enabled && zeroclaw_config::traits::is_unset_display_value(&dc.bot_token) {\n        eprintln!(\n            \"channels.discord.{alias}.bot_token unset — set the token or disable the channel\"\n        );\n    }\n}","typeGuard":"fn channel_ready(enabled: bool, bot_token: &str) -> bool {\n    !enabled || !zeroclaw_config::traits::is_unset_display_value(bot_token)\n}","tryCatchPattern":null,"preventionTips":["Source the Discord token from the same secret file pattern as Telegram so one env file covers all channels.","Rotate tokens by editing the env file and restarting — never leave placeholder values with enabled = true."],"tags":["config","channels","discord","credentials","doctor","zeroclaw"],"backgroundTag":"missing-credentials","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}