zeroclaw-labs/zeroclaw · error
invalid WeCom padding length
Error message
invalid WeCom padding length
What it means
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.
Source
Thrown at crates/zeroclaw-channels/src/wecom_ws.rs:1870
.remove(message_id)
.unwrap_or_default();
if !req_id.is_empty() {
self.ws_send_respond_msg(&req_id, message_id, "", true)
.await?;
}
Ok(())
}
}
// ── Helper functions ─────────────────────────────────────────────────
fn strip_wecom_padding(input: &[u8]) -> Result<&[u8]> {
let Some(last) = input.last() else {
anyhow::bail!("invalid WeCom padding: empty payload");
};
let pad_len = *last as usize;
if pad_len == 0 || pad_len > 32 || pad_len > input.len() {
anyhow::bail!("invalid WeCom padding length");
}
Ok(&input[..input.len() - pad_len])
}
fn is_wecom_data_version_conflict_error(err: &anyhow::Error) -> bool {
let msg = err.to_string();
msg.contains("errcode=6000") || msg.contains("data version conflict")
}
fn parse_inbound_payload(payload: Value) -> Result<ParsedInbound> {
let msg_type = payload
.get("msgtype")
.and_then(Value::as_str)
.unwrap_or("")
.to_string();
if msg_type.is_empty() {
anyhow::bail!("missing msgtype");
}View on GitHub (pinned to 88bb9c8533)
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
Defensive patterns
Strategy: try-catch
Try / catch
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.
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid WeCom padding: empty payload
- WeCom media aeskey too short: expected >= 32 bytes, got {}
- WeCom channel requires the `channel-wecom` feature
- WeCom WebSocket channel requires the `channel-wecom-ws` feat
- wecom_ws channel is not connected
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/7d4aec38828b5d9b.
Report an issue: GitHub.