w7corp/easywechat · error · DecryptException

The given payload is invalid: %s

Error message

The given payload is invalid: %s

What it means

Any failure inside MiniApp\Decryptor::decrypt() — AesCbc::decrypt throwing (wrong sessionKey/iv or corrupted ciphertext fails the AES-128-CBC padding check) or json_decode not yielding an array — is re-thrown as this DecryptException with the underlying message appended. It is the standard failure when decrypting wx.getUserProfile/getPhoneNumber-style encryptedData, and in practice almost always means the sessionKey does not correspond to the encryptedData being decrypted.

Source

Thrown at src/MiniApp/Decryptor.php:38

     *
     * @throws DecryptException
     */
    public static function decrypt(string $sessionKey, string $iv, string $ciphertext): array
    {
        try {
            $decrypted = AesCbc::decrypt(
                $ciphertext,
                base64_decode($sessionKey, false),
                base64_decode($iv, false)
            );

            $decrypted = json_decode($decrypted, true);

            if (! $decrypted || ! is_array($decrypted)) {
                throw new DecryptException('The given payload is invalid.');
            }
        } catch (Throwable $e) {
            throw new DecryptException(sprintf('The given payload is invalid: %s', $e->getMessage()));
        }

        return $decrypted;
    }
}

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Re-run codeToSession with a fresh code and retry decryption with the new session_key.
  2. Persist session_key keyed by openid and refresh it on every login.
  3. Verify the appid matches the mini program that produced the data.
  4. Check iv base64-decodes to 16 bytes and encryptedData is the untouched client string.

Example fix

// before: decrypting with a session_key from an earlier login
$data = Decryptor::decrypt($oldSessionKey, $iv, $encryptedData);
// after: refresh via code2Session on failure and retry once
try {
    $data = Decryptor::decrypt($sessionKey, $iv, $encryptedData);
} catch (DecryptException $e) {
    $session = $app->getUtils()->codeToSession($code);
    Cache::put("sk:{$session['openid']}", $session['session_key'], 300);
    $data = Decryptor::decrypt($session['session_key'], $iv, $encryptedData);
}
Defensive patterns

Strategy: retry

Validate before calling

if (strlen((string) base64_decode($sessionKey, true)) !== 24) { throw new InvalidArgumentException('session_key must base64-decode to 24 bytes'); }
if (strlen((string) base64_decode($iv, true)) !== 16) { throw new InvalidArgumentException('iv must base64-decode to 16 bytes'); }

Try / catch

try { $data = \EasyWeChat\MiniApp\Decryptor::decrypt($sessionKey, $iv, $encryptedData); } catch (\EasyWeChat\Kernel\Exceptions\DecryptException $e) { // one controlled retry with a refreshed session_key $fresh = $app->getUtils()->codeToSession($code); return \EasyWeChat\MiniApp\Decryptor::decrypt($fresh['session_key'], $iv, $encryptedData); }

Prevention

When it happens

Trigger: Using a stale session_key (the user logged in again, so code2Session issued a new one); iv from a different client call than encryptedData; appid of the issuing client different from the configured MiniApp; ciphertext/iv corrupted or URL-decoded so base64 padding was stripped.

Common situations: Calling code2Session twice and keeping the first session_key; session_key cached under a wrong or shared key across users; test data generated in dev tools used against production credentials; GET-parameter truncation of trailing '=' characters.

Related errors


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/a6dd367dfc705d72. Report an issue: GitHub.