{"record":{"id":"232209ce83e05486","repo":"zeroclaw-labs/zeroclaw","slug":"wecom-invalid-scope-format-scope","errorCode":null,"errorMessage":"WeCom: invalid scope format: {scope}","messagePattern":"WeCom: invalid scope format: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/wecom_ws.rs","lineNumber":2144,"sourceCode":"        \"jpg\"\n    } else if bytes.starts_with(b\"GIF87a\") || bytes.starts_with(b\"GIF89a\") {\n        \"gif\"\n    } else if bytes.len() >= 12 && &bytes[..4] == b\"RIFF\" && &bytes[8..12] == b\"WEBP\" {\n        \"webp\"\n    } else {\n        \"bin\"\n    }\n}\n\n/// Parse scope string into (chat_type, chatid) for aibot_send_msg.\n/// `user--{userid}` → (1, userid), `group--{chatid}` → (2, chatid)\nfn parse_scope(scope: &str) -> Result<(u32, &str)> {\n    if let Some(userid) = scope.strip_prefix(\"user--\") {\n        Ok((1, userid))\n    } else if let Some(chatid) = scope.strip_prefix(\"group--\") {\n        Ok((2, chatid))\n    } else {\n        anyhow::bail!(\"WeCom: invalid scope format: {scope}\")\n    }\n}\n\nfn summarize_attachment_url_for_log(url: &str) -> String {\n    let trimmed = url.trim();\n    if trimmed.is_empty() {\n        return \"empty-url\".to_string();\n    }\n    match reqwest::Url::parse(trimmed) {\n        Ok(parsed) => {\n            let host = parsed.host_str().unwrap_or(\"unknown-host\");\n            let query_state = if parsed.query().is_some() {\n                \"query=present\"\n            } else {\n                \"query=none\"\n            };\n            format!(\n                \"{}://{}{} ({query_state})\",","sourceCodeStart":2126,"sourceCodeEnd":2162,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/wecom_ws.rs#L2126-L2162","documentation":"WeCom WS destinations are addressed by a scope string; parse_scope accepts exactly 'user--<userid>' (direct message, type 1) or 'group--<chatid>' (group chat, type 2) — note the double dash. Any other shape bails with the offending scope verbatim.","triggerScenarios":"Sending/replying with a scope built as a raw userid, 'user-<id>' (single dash), an email-style WeCom address, or a chatid missing the 'group--' prefix.","commonSituations":"reply_scope or target config populated with a copied bare WeCom userid; scope strings constructed with a different separator in user code; scopes sourced from external systems that use plain IDs.","solutions":["Format scopes as 'user--<userid>' for direct and 'group--<chatid>' for groups — double dash, no spaces","Derive scope strings from inbound messages (echo the reply scope) instead of hand-building them","Validate/normalize scopes at the config or data boundary before they reach the channel"],"exampleFix":"// before\nlet scope = format!(\"user-{userid}\");\n// after\nlet scope = format!(\"user--{userid}\");","handlingStrategy":"validation","validationCode":"fn is_valid_wecom_scope(scope: &str) -> bool {\n    let id = scope\n        .strip_prefix(\"user--\")\n        .or_else(|| scope.strip_prefix(\"group--\"));\n    id.is_some_and(|id| !id.is_empty())\n}\nassert!(\n    is_valid_wecom_scope(&scope),\n    \"scope must be user--<id> or group--<id>\"\n);","typeGuard":"// Rust narrowing predicate for WeCom WS scopes\nfn wecom_scope_kind(scope: &str) -> Option<(&'static str, &str)> {\n    if let Some(id) = scope.strip_prefix(\"user--\") {\n        return Some((\"user\", id));\n    }\n    if let Some(id) = scope.strip_prefix(\"group--\") {\n        return Some((\"group\", id));\n    }\n    None\n}\n// usage: if let Some((kind, id)) = wecom_scope_kind(scope) { channel.send(...) }","tryCatchPattern":"Validate scope shape before sending (predicate above); if a send still fails with 'invalid scope format', log the exact string and fix the producer that built it — do not retry, the format is deterministic.","preventionTips":["Centralize scope construction in one helper that emits the double-dash format","Prefer echoing reply scopes from inbound messages over hand-building them","Unit-test the double-dash format wherever scopes are produced"],"tags":["wecom","scope","address-format","validation","send"],"backgroundTag":"invalid-recipient-format","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}