laravel/framework · error · DecryptException
Unable to use tag because the cipher algorithm does not supp
Error message
Unable to use tag because the cipher algorithm does not support AEAD.
What it means
Thrown by Encrypter::ensureTagIsValid() when the configured cipher is a non-AEAD algorithm (aes-128-cbc/aes-256-cbc) but the payload still carries a 'tag' field. CBC relies on a separate HMAC MAC for integrity, not an AEAD tag, so a present tag indicates the payload was produced under a GCM cipher and is being decrypted under CBC, or the payload is malformed.
Source
Thrown at src/Illuminate/Encryption/Encrypter.php:324
);
}
/**
* Ensure the given tag is a valid tag given the selected cipher.
*
* @param string $tag
* @return void
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
protected function ensureTagIsValid($tag)
{
if (self::$supportedCiphers[strtolower($this->cipher)]['aead'] && strlen($tag) !== 16) {
throw new DecryptException('Could not decrypt the data.');
}
if (! self::$supportedCiphers[strtolower($this->cipher)]['aead'] && is_string($tag)) {
throw new DecryptException('Unable to use tag because the cipher algorithm does not support AEAD.');
}
}
/**
* Determine if we should validate the MAC while decrypting.
*
* @return bool
*/
protected function shouldValidateMac()
{
return ! self::$supportedCiphers[strtolower($this->cipher)]['aead'];
}
/**
* Determine if the given value appears to be encrypted by this encrypter.
*
* @param mixed $value
* @return boolView on GitHub (pinned to bd6b5437e6)
Solutions
- Ensure the Encrypter's cipher matches the cipher that originally produced the payload.
- Re-encrypt any GCM-produced payloads into CBC format (or keep GCM) before changing APP_CIPHER.
- Strip an erroneous 'tag' only if you have verified the payload is genuinely CBC and the field was added erroneously - otherwise treat data as corrupt.
Example fix
// before - decrypting gcm payload under cbc cipher throws $enc = new Encrypter($key, 'aes-256-cbc'); $enc->decrypt($gcmEncryptedPayload); // after - keep cipher consistent with how data was encrypted $enc = new Encrypter($key, 'aes-256-gcm'); $plain = $enc->decrypt($gcmEncryptedPayload);
Defensive patterns
Strategy: validation
Validate before calling
// Don't attempt cbc decrypt on a payload that carries a tag
$decoded = json_decode(base64_decode($payload), true);
if (is_array($decoded) && !empty($decoded['tag']) && $cipher === 'aes-256-cbc') {
// payload is gcm; use a gcm encrypter instead
} Type guard
function payloadMatchesCipher(?array $decoded, string $cipher): bool
{
if (!is_array($decoded)) return false;
$aead = in_array(strtolower($cipher), ['aes-128-gcm', 'aes-256-gcm'], true);
$hasTag = isset($decoded['tag']) && $decoded['tag'] !== '';
return $aead ? $hasTag : !$hasTag;
} Try / catch
use Illuminate\Contracts\Encryption\DecryptException;
try {
return $cbcEncrypter->decrypt($payload);
} catch (DecryptException $e) {
if (str_contains($e->getMessage(), 'does not support AEAD')) {
// payload is gcm - retry with gcm encrypter
return $gcmEncrypter->decrypt($payload);
}
throw $e;
} Prevention
- Keep cipher and key rotation consistent across all encrypted data.
- Tag presence in payload reliably indicates gcm origin; honor it.
- Document the cipher in use at every layer that encrypts.
When it happens
Trigger: Calling decrypt() with an Encrypter configured for a CBC cipher on a payload that includes a non-empty 'tag' key (i.e. encrypted by a GCM cipher). Also triggered if hand-assembled JSON includes a spurious tag field.
Common situations: Downgrading APP_CIPHER from aes-256-gcm to aes-256-cbc while old GCM-encrypted data remains in sessions, cookies, or DB columns; mixing encrypters with different ciphers in the same app.
Related errors
- Unsupported cipher or incorrect key length. Supported cipher
- Could not encrypt the data.
- The MAC is invalid.
- Could not decrypt the data.
- The payload is invalid.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/c340a1e9193de825.json.
Report an issue: GitHub.