laravel/framework · error · DecryptException
The payload is invalid.
Error message
The payload is invalid.
What it means
getJsonPayload() throws DecryptException('The payload is invalid.') at line 244 when the input is not a string — decrypt() was given null, an array, an int, etc. This is the first guard before any base64/json decoding; it catches callers passing the wrong type entirely (e.g. feeding already-decoded data back into decrypt).
Source
Thrown at src/Illuminate/Encryption/Encrypter.php:244
* @return string
*/
protected function hash(#[\SensitiveParameter] $iv, #[\SensitiveParameter] $value, #[\SensitiveParameter] $key)
{
return hash_hmac('sha256', $iv.$value, $key);
}
/**
* Get the JSON array from the given payload.
*
* @param string $payload
* @return array
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function getJsonPayload($payload)
{
if (! is_string($payload)) {
throw new DecryptException('The payload is invalid.');
}
$payload = json_decode(base64_decode($payload), true);
// If the payload is not valid JSON or does not have the proper keys set we will
// assume it is invalid and bail out of the routine since we will not be able
// to decrypt the given value. We'll also check the MAC for this encryption.
if (! $this->validPayload($payload)) {
throw new DecryptException('The payload is invalid.');
}
return $payload;
}
/**
* Verify that the encryption payload is valid.
*
* @param mixed $payloadView on GitHub (pinned to bd6b5437e6)
Solutions
- Check the input is a non-empty string before calling decrypt: if (is_string($v) && $v !== '') { decrypt($v); }.
- Use Encrypter::appearsEncrypted($v) to confirm shape before attempting decryption.
- Treat null/missing inputs as 'no data' in your domain logic rather than piping them through decrypt().
- For optional cookies/headers, return a default and skip decryption when absent.
Example fix
// before
$value = decrypt($request->cookie('prefs')); // cookie may be null
// after
$raw = $request->cookie('prefs');
$value = is_string($raw) && Encrypter::appearsEncrypted($raw)
? decrypt($raw)
: defaultPrefs(); Defensive patterns
Strategy: type-guard
Validate before calling
$raw = $request->cookie('prefs');
if (! is_string($raw) || $raw === '') {
return defaultPrefs();
}
return decrypt($raw); Type guard
function isDecryptableString(mixed $value): bool
{
return is_string($value) && $value !== ''
&& \Illuminate\Encryption\Encrypter::appearsEncrypted($value);
} Prevention
- Never pass null/arrays/ints into decrypt() — guard with is_string first.
- Treat missing optional inputs as defaults, not as decrypt targets.
- Use appearsEncrypted() to validate shape before decryption.
When it happens
Trigger: Calling decrypt(null), decrypt([]) or decrypt(123) — typically because the caller read a missing cookie/header (null) or pulled an already-parsed value from somewhere and passed it straight to decrypt(). Common in cookie/session middleware reading optional inputs.
Common situations: Cookies not present on the request ($request->cookie('foo') returns null); a header missing; reading encrypted values from JSON requests where the field is absent; double-decoding (passing the decoded array back into decrypt).
Related errors
- The MAC is invalid.
- Could not decrypt the data.
- Unable to use tag because the cipher algorithm does not supp
- The given password does not match the current password.
- You requested {$requested} items, but there are only {$count
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/b1c2d17061b10bac.json.
Report an issue: GitHub.