# Session Loop Bug (Returned) ## Issue Description The session refresh loop bug has returned. After completing setup and the server restarts, the UI flashes/loops rapidly if you're on the dashboard, agents, or settings pages. User must manually logout and log back in to stop the loop. **Previous fix:** Commit 7b77641 - "fix: resolve 401 session refresh loop" - Added logout() call in Setup.tsx before configuration - Cleared auth state on 401 in store - Disabled retries in API client ## Current Behavior **Steps to reproduce:** 1. Complete setup wizard 2. Click "Restart Server" button (or restart manually) 3. Server goes down, Docker components restart 4. UI automatically redirects from setup to dashboard 5. **BUG:** Screen starts flashing/rapid refresh loop 6. Clicking Logout stops the loop 7. Logging back in works fine ## Suspected Cause The SetupCompletionChecker component is polling every 3 seconds and has a dependency array issue: ```typescript useEffect(() => { const checkSetupStatus = async () => { ... } checkSetupStatus(); const interval = setInterval(checkSetupStatus, 3000); return () => clearInterval(interval); }, [wasInSetupMode, location.pathname, navigate]); // ← Problem here ``` **Issue:** `wasInSetupMode` is in the dependency array. When it changes from `false` to `true` to `false`, it triggers new effect runs, creating multiple overlapping intervals without properly cleaning up the old ones. During docker restart: 1. Initial render: creates interval 1 2. Server goes down: can't fetch health, sets wasInSetupMode 3. Effect re-runs: interval 1 still running, creates interval 2 4. Server comes back: detects not in setup mode 5. Effect re-runs again: interval 1 & 2 still running, creates interval 3 6. Now 3+ intervals all polling every 3 seconds = rapid flashing ## Potential Fix Options ### Option 1: Remove wasInSetupMode from dependencies ```typescript useEffect(() => { let wasInSetup = false; const checkSetupStatus = async () => { // ... existing logic using wasInSetup local variable }; checkSetupStatus(); const interval = setInterval(checkSetupStatus, 3000); return () => clearInterval(interval); }, [location.pathname, navigate]); // Only pathname and navigate ``` ### Option 2: Add interval guard ```typescript const [intervalId, setIntervalId] = useState(null); useEffect(() => { // Clear any existing interval first if (intervalId) { clearInterval(intervalId); } const checkSetupStatus = async () => { ... }; checkSetupStatus(); const newInterval = setInterval(checkSetupStatus, 3000); setIntervalId(newInterval); return () => clearInterval(newInterval); }, [wasInSetupMode, location.pathname, navigate]); ``` ### Option 3: Increase polling interval during transitions ```typescript const pollingInterval = wasInSetupMode ? 5000 : 3000; // Slower during transition const interval = setInterval(checkSetupStatus, pollingInterval); ``` ### Option 4: Stop polling after successful redirect ```typescript if (wasInSetupMode && !currentSetupMode && location.pathname === '/setup') { console.log('Setup completed - redirecting to login'); navigate('/login', { replace: true }); // Don't set up interval again return; } ``` ## Testing After applying fix: ```bash # 1. Fresh setup docker-compose down -v --remove-orphans rm config/.env docker-compose build --no-cache cp config/.env.bootstrap.example config/.env docker-compose up -d # 2. Complete setup wizard # 3. Restart server via UI or manually docker-compose restart server # 4. Watch browser console for: # - Multiple "checking setup status" logs # - 401 errors # - Rapid API calls to /health endpoint # 5. Expected: No flashing, clean redirect to login ``` ## Related Files - `aggregator-web/src/components/SetupCompletionChecker.tsx` - Main component - `aggregator-web/src/lib/store.ts` - Auth store with logout() - `aggregator-web/src/pages/Setup.tsx` - Calls logout before configure - `aggregator-web/src/lib/api.ts` - API retry logic ## Notes This bug only manifests during the server restart after setup completion, making it hard to reproduce without a full cycle. The previous fix (commit 7b77641) addressed the 401 loop but didn't fully solve the interval cleanup issue.