{"record":{"id":"66f698b6ca386468","repo":"w7corp/easywechat","slug":"the-given-payload-is-invalid","errorCode":null,"errorMessage":"The given payload is invalid.","messagePattern":"The given payload is invalid\\.","errorType":"exception","errorClass":"DecryptException","httpStatus":null,"severity":"error","filePath":"src/MiniApp/Decryptor.php","lineNumber":35,"sourceCode":"{\n    /**\n     * @return array<string, mixed>\n     *\n     * @throws DecryptException\n     */\n    public static function decrypt(string $sessionKey, string $iv, string $ciphertext): array\n    {\n        try {\n            $decrypted = AesCbc::decrypt(\n                $ciphertext,\n                base64_decode($sessionKey, false),\n                base64_decode($iv, false)\n            );\n\n            $decrypted = json_decode($decrypted, true);\n\n            if (! $decrypted || ! is_array($decrypted)) {\n                throw new DecryptException('The given payload is invalid.');\n            }\n        } catch (Throwable $e) {\n            throw new DecryptException(sprintf('The given payload is invalid: %s', $e->getMessage()));\n        }\n\n        return $decrypted;\n    }\n}\n","sourceCodeStart":17,"sourceCodeEnd":44,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/MiniApp/Decryptor.php#L17-L44","documentation":"MiniApp\\Decryptor::decrypt() AES-128-CBC decrypts encryptedData with sessionKey/iv and json_decodes the plaintext; when the decrypted bytes are not a non-empty JSON array it throws this bare DecryptException. However that throw happens inside the try block, so the catch (Throwable) immediately re-wraps it — the bare message only ever surfaces nested inside [38] as 'The given payload is invalid: The given payload is invalid.'. Reaching this branch means AES succeeded yet the plaintext was not the expected JSON payload.","triggerScenarios":"sessionKey/iv decrypt without an OpenSSL padding error but belong to a different login round or appid (garbage that happens to unpad); encryptedData decrypted once already (double-decryption of an already-plaintext payload); a custom payload encrypted with the same scheme but containing non-JSON bytes.","commonSituations":"Mixing WeChat dev-tools appid and production appid; wrappers that pre-decode data; cached session_key reused across login rounds.","solutions":["Ensure you decrypt with the session_key from the same code2Session exchange that produced encryptedData/iv.","Pass encryptedData exactly as the client provided — no pre-decoding or double-decrypting.","Confirm the appid matches the mini app that issued the data.","Catch DecryptException and re-request the data with a fresh session (see [38])."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if ($sessionKey === '' || $iv === '' || $ciphertext === '') { throw new InvalidArgumentException('sessionKey/iv/ciphertext are all required'); }\nif (strlen((string) base64_decode($iv, true)) !== 16) { throw new InvalidArgumentException('iv must base64-decode to 16 bytes'); }","typeGuard":null,"tryCatchPattern":"try { $data = \\EasyWeChat\\MiniApp\\Decryptor::decrypt($sessionKey, $iv, $encryptedData); } catch (\\EasyWeChat\\Kernel\\Exceptions\\DecryptException $e) { // nested message '...invalid: The given payload is invalid.' means AES worked but plaintext was not JSON: wrong session context or appid $session = $app->getUtils()->codeToSession($freshCode); $data = \\EasyWeChat\\MiniApp\\Decryptor::decrypt($session['session_key'], $iv, $encryptedData); }","preventionTips":["Pair session_key and encryptedData from one login in storage keys","Never cache session_key longer than its validity window","Reject non-base64 iv early"],"tags":["php","miniapp","decryption","session-key","json"],"backgroundTag":"session-key-mismatch","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}