{"id":"c340a1e9193de825","repo":"laravel/framework","slug":"unable-to-use-tag-because-the-cipher-algorithm-doe","errorCode":null,"errorMessage":"Unable to use tag because the cipher algorithm does not support AEAD.","messagePattern":"Unable to use tag because the cipher algorithm does not support AEAD\\.","errorType":"exception","errorClass":"DecryptException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Encryption/Encrypter.php","lineNumber":324,"sourceCode":"        );\n    }\n\n    /**\n     * Ensure the given tag is a valid tag given the selected cipher.\n     *\n     * @param  string  $tag\n     * @return void\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\DecryptException\n     */\n    protected function ensureTagIsValid($tag)\n    {\n        if (self::$supportedCiphers[strtolower($this->cipher)]['aead'] && strlen($tag) !== 16) {\n            throw new DecryptException('Could not decrypt the data.');\n        }\n\n        if (! self::$supportedCiphers[strtolower($this->cipher)]['aead'] && is_string($tag)) {\n            throw new DecryptException('Unable to use tag because the cipher algorithm does not support AEAD.');\n        }\n    }\n\n    /**\n     * Determine if we should validate the MAC while decrypting.\n     *\n     * @return bool\n     */\n    protected function shouldValidateMac()\n    {\n        return ! self::$supportedCiphers[strtolower($this->cipher)]['aead'];\n    }\n\n    /**\n     * Determine if the given value appears to be encrypted by this encrypter.\n     *\n     * @param  mixed  $value\n     * @return bool","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Encryption/Encrypter.php#L306-L342","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before - decrypting gcm payload under cbc cipher throws\n$enc = new Encrypter($key, 'aes-256-cbc');\n$enc->decrypt($gcmEncryptedPayload);\n\n// after - keep cipher consistent with how data was encrypted\n$enc = new Encrypter($key, 'aes-256-gcm');\n$plain = $enc->decrypt($gcmEncryptedPayload);","handlingStrategy":"validation","validationCode":"// Don't attempt cbc decrypt on a payload that carries a tag\n$decoded = json_decode(base64_decode($payload), true);\nif (is_array($decoded) && !empty($decoded['tag']) && $cipher === 'aes-256-cbc') {\n    // payload is gcm; use a gcm encrypter instead\n}","typeGuard":"function payloadMatchesCipher(?array $decoded, string $cipher): bool\n{\n    if (!is_array($decoded)) return false;\n    $aead = in_array(strtolower($cipher), ['aes-128-gcm', 'aes-256-gcm'], true);\n    $hasTag = isset($decoded['tag']) && $decoded['tag'] !== '';\n    return $aead ? $hasTag : !$hasTag;\n}","tryCatchPattern":"use Illuminate\\Contracts\\Encryption\\DecryptException;\ntry {\n    return $cbcEncrypter->decrypt($payload);\n} catch (DecryptException $e) {\n    if (str_contains($e->getMessage(), 'does not support AEAD')) {\n        // payload is gcm - retry with gcm encrypter\n        return $gcmEncrypter->decrypt($payload);\n    }\n    throw $e;\n}","preventionTips":["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."],"tags":["encryption","decryption","aead","configuration","cipher-mismatch"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}