{"id":"77cb7ea12447b492","repo":"laravel/framework","slug":"the-mac-is-invalid","errorCode":null,"errorMessage":"The MAC is invalid.","messagePattern":"The MAC is invalid\\.","errorType":"exception","errorClass":"DecryptException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Encryption/Encrypter.php","lineNumber":191,"sourceCode":"\n                if ($validMac && $validKey === null) {\n                    $validKey = $key;\n                }\n\n                continue;\n            }\n\n            $decrypted = \\openssl_decrypt(\n                $payload['value'], strtolower($this->cipher), $key, 0, $iv, $tag ?? ''\n            );\n\n            if ($decrypted !== false) {\n                break;\n            }\n        }\n\n        if ($this->shouldValidateMac() && $validKey === null) {\n            throw new DecryptException('The MAC is invalid.');\n        }\n\n        if ($this->shouldValidateMac()) {\n            $decrypted = \\openssl_decrypt(\n                $payload['value'], strtolower($this->cipher), $validKey, 0, $iv, $tag ?? ''\n            );\n        }\n\n        if (($decrypted ?? false) === false) {\n            throw new DecryptException('Could not decrypt the data.');\n        }\n\n        return $unserialize ? unserialize($decrypted) : $decrypted;\n    }\n\n    /**\n     * Decrypt the given string without unserialization.\n     *","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Encryption/Encrypter.php#L173-L209","documentation":"During decrypt() with a non-AEAD cipher (CBC), Laravel validates the HMAC-MAC against the current and all previous keys. If none of the keys produces a matching MAC, $validKey stays null and DecryptException('The MAC is invalid.') is thrown. This is the canonical integrity/tamper-detection failure and almost always means the payload was encrypted with a different key (or tampered with).","triggerScenarios":"Calling decrypt($payload) where the payload was encrypted with a key no longer configured — e.g. APP_KEY was rotated without registering the old key via previousKeys(), or the payload was tampered with. For CBC ciphers only; AEAD (GCM) ciphers skip MAC validation (the tag covers it).","commonSituations":"APP_KEY rotated; .env overwritten on deploy without preserving old key; copying encrypted data (cookies, queued jobs, cached values) between environments with different keys; session/cookie failures after key rotation; tampered query-string payloads.","solutions":["Register the old key for decryption: call Encrypter::previousKeys([old_keys]) or set APP_PREVIOUS_KEYS in config, so legacy payloads can still be decrypted.","If rotation was intentional and old data is disposable, clear the affected cookies/sessions/queues so clients get fresh payloads.","Verify APP_KEY is identical across all servers/containers sharing the encrypted data.","Confirm the cipher hasn't changed (cipher change invalidates all MACs even with the same key material)."],"exampleFix":"// before — key rotated, legacy payloads fail\n// .env: APP_KEY=base64:NEW...\n\n// after — register previous keys for graceful decryption\n// config/app.php\n'previous_keys' => [\n    env('APP_PREVIOUS_KEYS'),\n],\n// .env\nAPP_KEY=base64:NEW...\nAPP_PREVIOUS_KEYS=base64:OLD...","handlingStrategy":"try-catch","validationCode":"// Register previous keys so legacy CBC payloads still decrypt\n// config/app.php: 'previous_keys' => [env('APP_PREVIOUS_KEYS')]\n// then verify each registered key's length matches the cipher","typeGuard":null,"tryCatchPattern":"try {\n    $value = decrypt($payload);\n} catch (\\Illuminate\\Contracts\\Encryption\\DecryptException $e) {\n    if (str_contains($e->getMessage(), 'MAC is invalid')) {\n        // key rotation gap — register APP_PREVIOUS_KEYS, or treat as expired session\n    }\n    throw $e;\n}","preventionTips":["When rotating APP_KEY, always register the old key in previous_keys for grace-period decryption.","Keep APP_KEY identical across all nodes sharing encrypted data.","Never change the cipher without re-encrypting existing data."],"tags":["encryption","app-key","key-rotation","integrity","decryption"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}