{"record":{"id":"b1c2d17061b10bac","repo":"laravel/framework","slug":"the-payload-is-invalid","errorCode":null,"errorMessage":"The payload is invalid.","messagePattern":"The payload is invalid\\.","errorType":"exception","errorClass":"DecryptException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Encryption/Encrypter.php","lineNumber":244,"sourceCode":"     * @return string\n     */\n    protected function hash(#[\\SensitiveParameter] $iv, #[\\SensitiveParameter] $value, #[\\SensitiveParameter] $key)\n    {\n        return hash_hmac('sha256', $iv.$value, $key);\n    }\n\n    /**\n     * Get the JSON array from the given payload.\n     *\n     * @param  string  $payload\n     * @return array\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\DecryptException\n     */\n    protected function getJsonPayload($payload)\n    {\n        if (! is_string($payload)) {\n            throw new DecryptException('The payload is invalid.');\n        }\n\n        $payload = json_decode(base64_decode($payload), true);\n\n        // If the payload is not valid JSON or does not have the proper keys set we will\n        // assume it is invalid and bail out of the routine since we will not be able\n        // to decrypt the given value. We'll also check the MAC for this encryption.\n        if (! $this->validPayload($payload)) {\n            throw new DecryptException('The payload is invalid.');\n        }\n\n        return $payload;\n    }\n\n    /**\n     * Verify that the encryption payload is valid.\n     *\n     * @param  mixed  $payload","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/laravel/framework/blob/e0f6eb3518ac29fbbca8529e97d0df7fc9f24481/src/Illuminate/Encryption/Encrypter.php#L226-L262","documentation":"Encrypter::getJsonPayload first checks is_string($payload). If the caller passed a non-string (array, object, null) to Encrypter::decrypt(), it throws DecryptException('The payload is invalid.') before any base64/JSON parsing. This guards the downstream json_decode from type errors.","triggerScenarios":"Calling Crypt::decrypt($nonString) where $nonString is null, an array (e.g. already-decoded payload), an object, or an integer; reading a missing cookie/config key that returns null and passing it straight to decrypt().","commonSituations":"decrypting Request::cookie('foo') when the cookie is absent (null); passing the result of json_decode twice; chaining decrypt onto a function that returns array|null; test fixtures that pass arrays directly.","solutions":["Coerce/null-check the input before calling decrypt: $c = Request::cookie('foo'); return $c ? Crypt::decrypt($c) : null;","Make sure the value passed is the raw base64 ciphertext string exactly as produced by encrypt().","If you stored the decoded payload, re-encode it before decrypting or store the original ciphertext instead."],"exampleFix":"// before\n$value = Crypt::decrypt(Request::cookie('session_payload'));\n\n// after\n$raw = Request::cookie('session_payload');\n$value = is_string($raw) ? Crypt::decrypt($raw) : null;","handlingStrategy":"type-guard","validationCode":"if (! is_string($payload) || $payload === '') {\n    return null; // or throw a domain-specific exception\n}\nreturn Crypt::decrypt($payload);","typeGuard":"function isDecryptableString(mixed $payload): bool {\n    return is_string($payload) && $payload !== '';\n}","tryCatchPattern":null,"preventionTips":["Null-check cookie/config reads before passing to decrypt().","Never pass arrays or decoded payloads back into decrypt().","Wrap external-facing decrypt calls in is_string checks."],"tags":["encryption","security","decryption","validation","input-validation"],"backgroundTag":null,"analyzedSha":"e0f6eb3518ac29fbbca8529e97d0df7fc9f24481","analyzedAt":"2026-08-11T20:52:37.562Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}