{"record":{"id":"596092ed8c3a42ce","repo":"Tencent/WeKnora","slug":"decrypt-message-w","errorCode":null,"errorMessage":"decrypt message: %w","messagePattern":"decrypt message: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/wecom/webhook_adapter.go","lineNumber":208,"sourceCode":"\treturn true\n}\n\n// ParseCallback parses a WeCom callback into a unified IncomingMessage.\nfunc (a *WebhookAdapter) ParseCallback(c *gin.Context) (*im.IncomingMessage, error) {\n\tbodyBytes, err := io.ReadAll(c.Request.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body: %w\", err)\n\t}\n\n\tvar body callbackRequestBody\n\tif err := xml.Unmarshal(bodyBytes, &body); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal xml: %w\", err)\n\t}\n\n\t// Decrypt the message\n\tdecrypted, err := a.decrypt(body.Encrypt)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decrypt message: %w\", err)\n\t}\n\n\t// Log raw decrypted message for debugging\n\tlogger.Debugf(c.Request.Context(), \"[WeCom] Raw decrypted callback: %s\", string(decrypted))\n\n\tvar msg wecomMessage\n\tif err := xml.Unmarshal(decrypted, &msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal decrypted message: %w\", err)\n\t}\n\n\tlogger.Debugf(c.Request.Context(), \"[WeCom] Parsed webhook message: msgid=%s msgtype=%s from=%s content=%q picurl=%q mediaid=%q\",\n\t\tmsg.MsgID, msg.MsgType, msg.FromUserName, msg.Content, msg.PicUrl, msg.MediaId)\n\n\t// Determine chat type\n\tchatType := im.ChatTypeDirect\n\tchatID := \"\"\n\tisGroup := msg.ChatID != \"\"\n\tif isGroup {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/wecom/webhook_adapter.go#L190-L226","documentation":"In the WeCom webhook adapter's ParseCallback, the encrypted payload field (body.Encrypt) is decrypted with the adapter's crypto key after XML unmarshalling. This error wraps any failure of that decryption — almost always a wrong or mismatched EncodingAESKey between your WeCom app config and the adapter's configured key.","triggerScenarios":"POSTing a WeCom callback whose <Encrypt> field cannot be decrypted with the configured aes_key — wrong key configured, callback from a different WeCom app/corp, or a tampered/replayed payload.","commonSituations":"Rotating the EncodingAESKey in the WeCom admin console without updating the channel credentials; copying the key from the wrong application; pointing a test callback at a different corp's callback URL.","solutions":["Verify the adapter's configured EncodingAESKey matches the one shown in the WeCom admin console for the exact application receiving the callback.","Re-check that corp_id/token/aes_key triple all belong to the same WeCom app.","Inspect the inner wrapped error (%w chain) to distinguish padding/base64 failures from key mismatch.","If you rotated keys, redeploy/reload the adapter so the new key is used."],"exampleFix":"// before\nch.Credentials = `{\"corp_id\":\"x\",\"token\":\"t\",\"aes_key\":\"<old-key>\"}`\n// after (key copied from WeCom app settings)\nch.Credentials = `{\"corp_id\":\"x\",\"token\":\"t\",\"aes_key\":\"<current-encoding-aes-key>\"}`","handlingStrategy":"try-catch","validationCode":"// before trusting callbacks, confirm key config matches WeCom console\nif a.aesKey == \"\" || len(a.aesKey) != 43 {\n    return fmt.Errorf(\"wecom adapter misconfigured: EncodingAESKey must be the 43-char base64 key from WeCom admin\")\n}","typeGuard":null,"tryCatchPattern":"msg, err := adapter.ParseCallback(c)\nif err != nil {\n    if strings.Contains(err.Error(), \"decrypt message\") {\n        log.Errorf(\"wecom callback decryption failed (check EncodingAESKey/corp_id match): %v\", err)\n        c.String(http.StatusBadRequest, \"decrypt failed\")\n        return\n    }\n    c.String(http.StatusBadRequest, \"bad callback\")\n}","preventionTips":["Keep token/aes_key/corp_id sourced from the same WeCom application.","Re-deploy adapters after key rotation in the WeCom console.","Alert on decryption failures — they often indicate replay or misconfiguration.","Log the inner wrapped error, never just the top-level message."],"tags":["wecom","decryption","webhook","crypto"],"backgroundTag":"webhook-decryption-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}