Tencent/WeKnora · error
plaintext too short
Error message
plaintext too short
What it means
WeCom plaintext has the layout random(16 bytes) + msg_len(4 bytes, big-endian) + msg + corp_id, so at least 20 bytes are required before the message-length field can even be read. decrypt() returns this error when the unpadded plaintext is shorter than 20 bytes. It almost always accompanies a key mismatch that yielded garbage padding, or a genuinely truncated payload.
Source
Thrown at internal/im/wecom/webhook_adapter.go:484
iv := a.aesKey[:aes.BlockSize]
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
// Remove and verify PKCS#7 padding
padLen := int(ciphertext[len(ciphertext)-1])
if padLen > wecomPKCS7BlockSize || padLen == 0 || padLen > len(ciphertext) {
return nil, fmt.Errorf("invalid padding")
}
for i := 0; i < padLen; i++ {
if ciphertext[len(ciphertext)-1-i] != byte(padLen) {
return nil, fmt.Errorf("invalid padding")
}
}
plaintext := ciphertext[:len(ciphertext)-padLen]
// WeCom format: random(16) + msg_len(4) + msg + corp_id
if len(plaintext) < 20 {
return nil, fmt.Errorf("plaintext too short")
}
msgLen := binary.BigEndian.Uint32(plaintext[16:20])
if uint32(len(plaintext)) < 20+msgLen {
return nil, fmt.Errorf("message length mismatch")
}
msgBytes := plaintext[20 : 20+msgLen]
// Verify corp_id from plaintext tail
corpIDBytes := plaintext[20+msgLen:]
if string(corpIDBytes) != a.corpID {
return nil, fmt.Errorf("corp_id mismatch: expected %s, got %s", a.corpID, string(corpIDBytes))
}
return msgBytes, nil
}
View on GitHub (pinned to 988cbb0330)
Solutions
- Fix the underlying key mismatch first — a correct key on real WeCom data always yields >= 20 bytes of plaintext
- Check for truncation of the Encrypt field upstream (proxies, logs, form parsing) and pass the raw body bytes
- Validate the decrypted length sanity in tests by encrypting a sample via the official WeCom crypto sample
- Confirm the base64 decode uses StdEncoding, not URL-safe variants
Defensive patterns
Strategy: try-catch
Type guard
func hasWeComPlaintextLayout(plaintext []byte) bool { return len(plaintext) >= 20 } Try / catch
msg, err := adapter.ParseCallback(sig, ts, nonce, enc)
if err != nil && strings.Contains(err.Error(), "plaintext too short") {
// almost always a key mismatch; treat as bad request
http.Error(w, "bad payload", http.StatusBadRequest)
return
} Prevention
- Fix 'invalid padding' root causes (key mismatch) — this error rarely occurs alone
- Never feed hand-crafted short payloads to decrypt outside tests
When it happens
Trigger: PKCS#7 padding with padLen close to 16 stripping nearly all bytes from a short/garbage plaintext; decrypting non-WeCom data that happens to pass padding checks; severely truncated callback payloads.
Common situations: Wrong EncodingAESKey producing valid-looking-but-garbage padding; a test posting tiny payloads; intermediary systems compressing or transforming the encrypted body.
Related errors
- message length mismatch
- ciphertext too short
- ciphertext length is not a multiple of AES block size
- invalid padding
- decrypt message: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/85252e2592f13222.
Report an issue: GitHub.