{"record":{"id":"9e6a61a58d48a3cf","repo":"zeroclaw-labs/zeroclaw","slug":"qq-channel-requires-the-channel-qq-feature","errorCode":null,"errorMessage":"QQ channel requires the `channel-qq` feature","messagePattern":"QQ channel requires the `channel-qq` feature","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/orchestrator/mod.rs","lineNumber":9183,"sourceCode":"                .qq\n                .get(\"default\")\n                .context(\"QQ channel is not configured\")?;\n            let alias = \"default\".to_string();\n            let peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> = {\n                let cfg_arc = config_arc.clone();\n                let alias = alias.clone();\n                Arc::new(move || cfg_arc.read().channel_external_peers(\"qq\", &alias))\n            };\n            Ok(Arc::new(QQChannel::new(\n                qq.app_id.clone(),\n                qq.app_secret.clone(),\n                alias,\n                peer_resolver,\n            )))\n        }\n        #[cfg(not(feature = \"channel-qq\"))]\n        \"qq\" => {\n            anyhow::bail!(\"QQ channel requires the `channel-qq` feature\");\n        }\n        \"lark\" => {\n            #[cfg(feature = \"channel-lark\")]\n            {\n                let lk = config\n                    .channels\n                    .lark\n                    .get(\"default\")\n                    .context(\"Lark channel is not configured\")?;\n                let alias = \"default\".to_string();\n                let peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync> = {\n                    let cfg_arc = config_arc.clone();\n                    let alias = alias.clone();\n                    Arc::new(move || cfg_arc.read().channel_external_peers(\"lark\", &alias))\n                };\n                Ok(Arc::new(\n                    LarkChannel::from_config(lk, alias, peer_resolver)\n                        .with_workspace_dir(one_shot_channel_workspace_dir(","sourceCodeStart":9165,"sourceCodeEnd":9201,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/orchestrator/mod.rs#L9165-L9201","documentation":"Raised by build_channel_by_id (crates/zeroclaw-channels/src/orchestrator/mod.rs:8889), the channel factory used by start_channels, when the resolved config selects the QQ channel but the zeroclaw-channels crate was compiled without the `channel-qq` Cargo feature. The config schema accepts [channels.qq] unconditionally, so the mismatch surfaces only at runtime: the `#[cfg(not(feature = \"channel-qq\"))]` arm still matches channel_id \"qq\" and bails with the exact feature name instead of reporting an unknown channel.","triggerScenarios":"Calling start_channels, build_channel_map, or build_channel_by_id with channel_id = \"qq\" (from an [agents.<alias>] channels binding or a [channels.qq] block) in a binary built without `--features channel-qq`. The QQ config parses fine; the bail happens when the factory tries to construct the channel actor.","commonSituations":"Building zeroclaw with the default feature set (default-channels compiles only acp-server, discord, email, filesystem, telegram, webhook), using a prebuilt/distro binary compiled with a channel subset, or enabling channels-full later and assuming QQ was already in it. QQ is in `channels-full` but not in `default-channels`.","solutions":["Rebuild with the feature enabled: cargo build --release -p zeroclaw-channels --features channel-qq (enable it on the binary crate you actually run, e.g. -p zeroclaw --features zeroclaw-channels/channel-qq)","Or enable the bundle: cargo build --release --features channels-full (includes channel-qq)","Or remove/disable the [channels.qq] block and any \"qq\" channel bindings from the config so the factory never selects the arm","Before rebuilding, confirm the gap with zeroclaw_channels::listing::is_channel_type_compiled(\"qq\") or the compiled-channel listing CLI"],"exampleFix":"# before\n cargo build --release   # default features: qq arm compiled out\n # config.toml has [channels.qq] -> runtime bail\n\n # after\n cargo build --release --features channels-full   # or --features channel-qq","handlingStrategy":"validation","validationCode":"use zeroclaw_channels::listing::is_channel_type_compiled;\n\n// before building channels, gate on compilation\nif !is_channel_type_compiled(\"qq\") {\n    eprintln!(\"this binary lacks the `channel-qq` feature; rebuild or drop [channels.qq]\");\n    return;\n}","typeGuard":"fn qq_available() -> bool {\n    zeroclaw_channels::listing::is_channel_type_compiled(\"qq\")\n}","tryCatchPattern":"match build_channel_by_id(&config_arc, \"qq\") {\n    Ok(ch) => { /* use channel */ }\n    Err(e) if e.to_string().contains(\"requires the `channel-qq` feature\") => {\n        // build-time issue: skip channel, log rebuild hint, never retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run zeroclaw_channels::listing::configured_uncompiled_channels(&config.channels) at startup and fail fast with the full list instead of one error per channel","Pin the feature list next to the config in deployment scripts so config and build cannot drift","Prefer --features channels-full for a config-driven deployment that adds channels over time"],"tags":["rust","cargo-features","feature-gate","zeroclaw","channels","qq"],"backgroundTag":"cargo-feature-not-enabled","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}