{"record":{"id":"24c0787de7bc1047","repo":"zeroclaw-labs/zeroclaw","slug":"wecom-websocket-channel-requires-the-channel-weco","errorCode":null,"errorMessage":"WeCom WebSocket channel requires the `channel-wecom-ws` feature","messagePattern":"WeCom WebSocket channel requires the `channel-wecom-ws` feature","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/orchestrator/mod.rs","lineNumber":9313,"sourceCode":"                        WeComWsRuntimePolicy::from_config(&snapshot, external_peers)\n                    }\n                })\n            };\n            Ok(Arc::new(WeComWsChannel::new_with_alias(\n                wc,\n                alias.clone(),\n                policy_resolver,\n                &config.channel_workspace_dir(&format!(\"wecom_ws.{alias}\")),\n            )?))\n        }\n        #[cfg(not(feature = \"channel-wecom-ws\"))]\n        channel_id\n            if channel_id == \"wecom_ws\"\n                || channel_id == \"wecom-ws\"\n                || channel_id.starts_with(\"wecom_ws.\")\n                || channel_id.starts_with(\"wecom-ws.\") =>\n        {\n            anyhow::bail!(\"WeCom WebSocket channel requires the `channel-wecom-ws` feature\");\n        }\n        #[cfg(feature = \"channel-wechat\")]\n        \"wechat\" => {\n            let wc = config\n                .channels\n                .wechat\n                .get(\"default\")\n                .context(\"WeChat 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(\"wechat\", &alias))\n            };\n            let workspace_dir = one_shot_channel_workspace_dir(&config, \"wechat\", &alias);\n            Ok(Arc::new(\n                WeChatChannel::new(\n                    alias,","sourceCodeStart":9295,"sourceCodeEnd":9331,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/orchestrator/mod.rs#L9295-L9331","documentation":"Raised by build_channel_by_id when the channel id matches the WeCom WebSocket guard — literal \"wecom_ws\"/\"wecom-ws\" or any alias prefixed \"wecom_ws.\"/\"wecom-ws.\" — and the binary lacks the `channel-wecom-ws` feature. That feature is not a cfg-only flag: it pulls dep:aes and dep:cbc for decrypting WeCom WebSocket payloads (see wecom_ws.rs). The guard matches before the id falls through to unknown-channel handling, so aliased instances get the feature hint too.","triggerScenarios":"start_channels / build_channel_by_id with channel_id equal to \"wecom_ws\", \"wecom-ws\", or an alias like \"wecom_ws.ops\" / \"wecom-ws.ops\", in a build compiled without channel-wecom-ws.","commonSituations":"Default-feature builds; or enabling only `channel-wecom` (callback mode) and assuming it covers WebSocket mode; or multi-alias configs ([channels.wecom_ws.ops]) on a slim binary where the prefixed-alias guard is the only thing that recognizes the id.","solutions":["Rebuild with cargo build --release --features channel-wecom-ws (pulls aes/cbc deps)","Or use --features channels-full which includes channel-wecom-ws","Or delete the [channels.wecom_ws.*] / wecom-ws blocks and their agent bindings","Pre-check zeroclaw_channels::listing::is_channel_type_compiled(\"wecom_ws\") — listing.rs registers both wecom_ws keys"],"exampleFix":"# before\n cargo build --release --features channel-wecom\n # config: [channels.wecom_ws.default] -> bail\n\n # after\n cargo build --release --features \"channel-wecom,channel-wecom-ws\"","handlingStrategy":"validation","validationCode":"use zeroclaw_channels::listing::is_channel_type_compiled;\n\nlet id = \"wecom_ws.ops\";\nlet is_ws = id == \"wecom_ws\" || id == \"wecom-ws\"\n    || id.starts_with(\"wecom_ws.\") || id.starts_with(\"wecom-ws.\");\nif is_ws && !is_channel_type_compiled(\"wecom_ws\") {\n    eprintln!(\"rebuild with --features channel-wecom-ws for {id}\");\n}","typeGuard":"fn wecom_ws_id(id: &str) -> bool {\n    id == \"wecom_ws\" || id == \"wecom-ws\"\n        || id.starts_with(\"wecom_ws.\") || id.starts_with(\"wecom-ws.\")\n}\n\nfn wecom_ws_available() -> bool {\n    zeroclaw_channels::listing::is_channel_type_compiled(\"wecom_ws\")\n}","tryCatchPattern":"match build_channel_by_id(&config_arc, \"wecom_ws.ops\") {\n    Ok(ch) => { /* use */ }\n    Err(e) if e.to_string().contains(\"requires the `channel-wecom-ws` feature\") => {\n        // skip; rebuild needed\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Alias validation should accept all four spellings the guard accepts, so your pre-check matches the factory's routing","channel-wecom-ws pulls aes/cbc — keep it enabled in the same profile that builds wecom_ws configs"],"tags":["rust","cargo-features","feature-gate","zeroclaw","channels","wecom","websocket"],"backgroundTag":"cargo-feature-not-enabled","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}