{"record":{"id":"cfb1fe38b24d9a3d","repo":"Tencent/WeKnora","slug":"corp-id-mismatch-expected-s-got-s","errorCode":null,"errorMessage":"corp_id mismatch: expected %s, got %s","messagePattern":"corp_id mismatch: expected (.+?), got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/wecom/webhook_adapter.go","lineNumber":497,"sourceCode":"\t}\n\tplaintext := ciphertext[:len(ciphertext)-padLen]\n\n\t// WeCom format: random(16) + msg_len(4) + msg + corp_id\n\tif len(plaintext) < 20 {\n\t\treturn nil, fmt.Errorf(\"plaintext too short\")\n\t}\n\n\tmsgLen := binary.BigEndian.Uint32(plaintext[16:20])\n\tif uint32(len(plaintext)) < 20+msgLen {\n\t\treturn nil, fmt.Errorf(\"message length mismatch\")\n\t}\n\n\tmsgBytes := plaintext[20 : 20+msgLen]\n\n\t// Verify corp_id from plaintext tail\n\tcorpIDBytes := plaintext[20+msgLen:]\n\tif string(corpIDBytes) != a.corpID {\n\t\treturn nil, fmt.Errorf(\"corp_id mismatch: expected %s, got %s\", a.corpID, string(corpIDBytes))\n\t}\n\n\treturn msgBytes, nil\n}\n\n// callbackRequestBody is the XML structure of a WeCom callback request body.\ntype callbackRequestBody struct {\n\tXMLName    xml.Name `xml:\"xml\"`\n\tToUserName string   `xml:\"ToUserName\"`\n\tEncrypt    string   `xml:\"Encrypt\"`\n\tAgentID    string   `xml:\"AgentID\"`\n}\n\n// wecomMessage is the decrypted WeCom message structure.\n// Supports text, image, voice, video, location, and link message types.\n// Reference: https://developer.work.weixin.qq.com/document/path/90375\ntype wecomMessage struct {\n\tXMLName      xml.Name `xml:\"xml\"`","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/wecom/webhook_adapter.go#L479-L515","documentation":"The WeCom plaintext ends with the corp_id (corporation's CorpID) of the intended recipient; decrypt() compares it against the adapter's configured corpID and rejects mismatches. This prevents cross-tenant message confusion — a callback intended for one app/corp being processed by another. The error message includes both expected and received values for diagnosis.","triggerScenarios":"Callback from corp A delivered to an adapter configured with corp B's credentials; multi-corp deployments sharing one webhook URL; configured corp_id typo or stale value after the company changed its WeCom account.","commonSituations":"One endpoint serving multiple WeCom corps without routing by the XML ToUserName; copying another environment's corp ID into config; tenant onboarding with wrong credentials.","solutions":["Compare the 'got' value in the error with your WeCom admin CorpID — fix the config if expected is wrong","If multi-corp: route callbacks to adapters by the ToUserName field in the callback XML before decrypting","Confirm the Token/EncodingAESKey/corpID triple all belong to the same WeCom self-built app","Update deployment env vars for the corp whose credentials changed"],"exampleFix":"// before: one global corp id\nadapter := wecom.NewWebhookAdapter(token, aesKey, \"corp_old\")\n// after: per-corp routing\nadapter, ok := adapters[callback.ToUserName]\nif !ok { http.Error(w, \"unknown corp\", 404); return }","handlingStrategy":"validation","validationCode":"// verify corp identity after decrypt, before processing\n// (library already enforces this; ensure config corpID is correct at startup)\nif corpID == \"\" || corpID != expectedCorpID { return errors.New(\"misconfigured corpID\") }","typeGuard":null,"tryCatchPattern":"msg, err := adapter.ParseCallback(sig, ts, nonce, enc)\nif err != nil && strings.Contains(err.Error(), \"corp_id mismatch\") {\n    logger.Errorf(\"callback for wrong corp: %v\", err)\n    http.Error(w, \"wrong tenant\", http.StatusForbidden)\n    return\n}","preventionTips":["Copy CorpID exactly from the WeCom admin console ('my company' page)","In multi-tenant setups, instantiate one adapter per corp keyed by CorpID/ToUserName","Include corpID in deployment config review checklists"],"tags":["multi-tenancy","corp-id-mismatch","validation","wecom"],"backgroundTag":"corp-id-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}