{"record":{"id":"7d4aec38828b5d9b","repo":"zeroclaw-labs/zeroclaw","slug":"invalid-wecom-padding-length","errorCode":null,"errorMessage":"invalid WeCom padding length","messagePattern":"invalid WeCom padding length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/wecom_ws.rs","lineNumber":1870,"sourceCode":"            .remove(message_id)\n            .unwrap_or_default();\n        if !req_id.is_empty() {\n            self.ws_send_respond_msg(&req_id, message_id, \"\", true)\n                .await?;\n        }\n        Ok(())\n    }\n}\n\n// ── Helper functions ─────────────────────────────────────────────────\n\nfn strip_wecom_padding(input: &[u8]) -> Result<&[u8]> {\n    let Some(last) = input.last() else {\n        anyhow::bail!(\"invalid WeCom padding: empty payload\");\n    };\n    let pad_len = *last as usize;\n    if pad_len == 0 || pad_len > 32 || pad_len > input.len() {\n        anyhow::bail!(\"invalid WeCom padding length\");\n    }\n    Ok(&input[..input.len() - pad_len])\n}\n\nfn is_wecom_data_version_conflict_error(err: &anyhow::Error) -> bool {\n    let msg = err.to_string();\n    msg.contains(\"errcode=6000\") || msg.contains(\"data version conflict\")\n}\n\nfn parse_inbound_payload(payload: Value) -> Result<ParsedInbound> {\n    let msg_type = payload\n        .get(\"msgtype\")\n        .and_then(Value::as_str)\n        .unwrap_or(\"\")\n        .to_string();\n    if msg_type.is_empty() {\n        anyhow::bail!(\"missing msgtype\");\n    }","sourceCodeStart":1852,"sourceCodeEnd":1888,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/wecom_ws.rs#L1852-L1888","documentation":"strip_wecom_padding requires the final byte of the decrypted payload to be a pad length in 1..=32 that does not exceed the payload length. A value of 0, over 32, or larger than the input means the plaintext is corrupt — with a correct AES key WeCom's padding is always valid, so this almost always indicates a wrong key or truncated ciphertext.","triggerScenarios":"Decrypting with a mismatched or truncated aes_key (the code uses only the first 32 decoded bytes); ciphertext truncated in transit; a payload that is not WeCom-encrypted data reaching the decrypt path.","commonSituations":"EncodingAESKey copied from another app/environment; a key with trailing characters that shifts which 32 bytes are used; proxies truncating large frames; version skew changing the encryption envelope.","solutions":["Re-enter the aes_key for the exact WeCom app — the dominant cause; confirm it decodes to 32 bytes","Confirm the full ciphertext arrived (compare logged lengths; check for frame truncation)","If only some messages fail, capture the failing payload and test decryption offline with the configured key","After fixing credentials, restart the channel and verify with a fresh message"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch the 'invalid WeCom padding length' bail per message and skip it deterministically; a failure rate near 100% means the aes_key is wrong — halt the channel, rotate credentials, and re-verify with a known-good test message.","preventionTips":["Rotate aes_key, token, and corp/app id together as one credential set","Test decryption with a known sample message after every credential rotation","Catch and skip individual corrupt payloads; investigate when failures cluster"],"tags":["wecom","decryption","padding","aes","corrupt-data","key-mismatch"],"backgroundTag":"decryption-padding-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}