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 bool

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Ensure the Encrypter's cipher matches the cipher that originally produced the payload.
  2. Re-encrypt any GCM-produced payloads into CBC format (or keep GCM) before changing APP_CIPHER.
  3. 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

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


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/c340a1e9193de825.json. Report an issue: GitHub.