hasSession()) { // Force session start to catch any decryption/database errors $request->session()->start(); } return $next($request); } catch (DecryptException $e) { return $this->handleSessionError($request, $e, 'decrypt'); } catch (QueryException $e) { // Only catch session-related query exceptions if ($this->isSessionError($e)) { return $this->handleSessionError($request, $e, 'database'); } throw $e; } catch (\PDOException $e) { // Catch PDO exceptions that might be session-related if ($this->isSessionError($e)) { return $this->handleSessionError($request, $e, 'pdo'); } throw $e; } } /** * Handle a session error by clearing cookies and redirecting. */ protected function handleSessionError(Request $request, \Throwable $e, string $type): Response { Log::warning("[ResilientSession] Session {$type} error - clearing cookies", [ 'message' => $e->getMessage(), 'uri' => $request->getRequestUri(), 'ip' => $request->ip(), ]); $sessionCookie = config('session.cookie', 'laravel_session'); // For AJAX/API requests, return JSON error if ($request->expectsJson() || $request->is('api/*')) { return response()->json([ 'message' => 'Session expired. Please retry your request.', 'error' => 'session_expired', ], 419) ->withCookie(cookie()->forget($sessionCookie)) ->withCookie(cookie()->forget('XSRF-TOKEN')); } // For web requests, redirect to same page with cleared cookies return redirect($request->getRequestUri()) ->withCookie(cookie()->forget($sessionCookie)) ->withCookie(cookie()->forget('XSRF-TOKEN')); } /** * Check if an exception is likely session-related. */ protected function isSessionError(\Throwable $e): bool { $message = strtolower($e->getMessage()); $sessionTable = config('session.table', 'sessions'); return str_contains($message, $sessionTable) || str_contains($message, 'session') || str_contains($message, 'payload'); } }