{"record":{"id":"ce0f3b7b04078300","repo":"zeroclaw-labs/zeroclaw","slug":"missing-channels-channel-type-alias-section","errorCode":null,"errorMessage":"Missing [channels.{channel_type}.{alias}] section in config.toml — configure the channel before pairing","messagePattern":"Missing \\[channels\\.(.+?)\\.(.+?)\\] section in config\\.toml — configure the channel before pairing","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/identity_persist.rs","lineNumber":70,"sourceCode":") -> anyhow::Result<bool> {\n    use zeroclaw_config::multi_agent::{PeerGroupConfig, PeerUsername};\n    use zeroclaw_config::providers::ChannelRef;\n\n    let normalized = identity.trim();\n    if normalized.is_empty() {\n        anyhow::bail!(\"Cannot persist empty {channel_type} identity\");\n    }\n    // Existence comes from the canonical channel registry\n    // (`Config::channels_by_alias()` walks every configured\n    // `[channels.<type>.<alias>]` block regardless of type), so this writer\n    // holds no channel-type list of its own and a future QR-pairing channel\n    // needs no edit here.\n    let configured = cfg\n        .channels_by_alias()\n        .iter()\n        .any(|info| info.channel_type == channel_type && info.alias == alias);\n    if !configured {\n        anyhow::bail!(\n            \"Missing [channels.{channel_type}.{alias}] section in config.toml — \\\n             configure the channel before pairing\"\n        );\n    }\n\n    // Already authorized through any group the reader matches (including\n    // type-wide groups)? Then there is nothing to persist. This reuses the\n    // reader itself, so writer and reader cannot disagree about what\n    // \"already authorized\" means.\n    if cfg\n        .channel_external_peers(channel_type, alias)\n        .iter()\n        .any(|peer| peer == normalized)\n    {\n        return Ok(false);\n    }\n\n    let dotted_ref = format!(\"{channel_type}.{alias}\");","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/identity_persist.rs#L52-L88","documentation":"merge_external_peer refuses to persist a paired identity for a channel instance that does not exist in canonical config: it walks cfg.channels_by_alias() (every [channels.<type>.<alias>] block) and requires an entry matching both channel_type and alias. The writer will not create authorization state for a channel the runtime reader would never load, so pairing fails fast with a pointer to the missing TOML section.","triggerScenarios":"A QR pairing completes for alias 'main' of type 'wechat' (or 'whatsapp') but config.toml has no [channels.wechat.main] block — e.g. the handle was constructed programmatically with an alias that differs from the configured one ('default' vs 'main'), or the channel section was deleted after the process started.","commonSituations":"Alias typo between the channel handle and the TOML block; a pairing test that builds a Config without the channel section; operator removed the channel block while a pairing flow was still in flight.","solutions":["Add the missing [channels.<channel_type>.<alias>] section to config.toml with its required fields and enabled = true, then re-run the pairing","Check the alias spelling — the error text names the exact channel_type/alias pair persistence looked for; it must match the TOML key character-for-character","If the section exists but the error persists, confirm the running process actually reloaded config.toml (restart the runtime)"],"exampleFix":"# before (config.toml) — no wechat section\n[peer_groups.default]\nagents = [\"main\"]\n\n# after\n[channels.wechat.main]\nenabled = true\n# ...required wechat fields...\n\n[peer_groups.default]\nagents = [\"main\"]","handlingStrategy":"validation","validationCode":"// Before starting a pairing flow, confirm the channel exists canonically:\nlet configured = cfg.channels_by_alias()\n    .iter()\n    .any(|info| info.channel_type == channel_type && info.alias == alias);\nanyhow::ensure!(configured, \"configure [channels.{channel_type}.{alias}] before pairing\");","typeGuard":null,"tryCatchPattern":"match persist_external_peer(persist.as_deref(), channel_type, alias, identity).await {\n    Err(e) if e.to_string().contains(\"Missing [channels\") => {\n        // stop the pairing wizard and prompt the operator to add the TOML section\n    }\n    other => other?,\n}","preventionTips":["Make channel section presence a precondition of any pairing UI, checked before the QR is shown","Keep alias constants in one place so the handle alias and the TOML key cannot drift"],"tags":["identity-persist","configuration","qr-pairing","config-toml"],"backgroundTag":"missing-config-section","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}