From 2c27d6a2eb2b96a2b5f06468ffbe3d306d221056 Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:27:55 +0000 Subject: [PATCH] fix(replay): abort the recordings load when the playlist unmounts The loadSessionRecordings loader read values.filters after awaiting the API call but before its breakpoint. When the playlist unmounted mid-request the store path was already gone, so the read threw and was reported as an exception. Moving breakpoint() ahead of the read discards the superseded response instead. Generated-By: PostHog Code Task-Id: 93b8671f-a0de-4bca-84c6-c6d40b113d3f --- .../sessionRecordingsPlaylistLogic.test.ts | 27 +++++++++++++++++++ .../sessionRecordingsPlaylistLogic.ts | 6 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.test.ts b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.test.ts index d3a62ccf88e2..6d496ed971b2 100644 --- a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.test.ts +++ b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.test.ts @@ -986,6 +986,33 @@ describe('sessionRecordingsPlaylistLogic', () => { }) }) + describe('unmounting while a request is in flight', () => { + it('abandons the response instead of reading state that is already gone', async () => { + let requestStarted: () => void = () => {} + const started = new Promise((resolve) => (requestStarted = resolve)) + let finishRequest: (response: any) => void = () => {} + + jest.spyOn(api.recordings, 'list').mockImplementation(() => { + requestStarted() + return new Promise((resolve) => (finishRequest = resolve)) + }) + const captureException = jest.spyOn(posthog, 'captureException').mockImplementation() + + logic = sessionRecordingsPlaylistLogic({ + logicKey: 'unmount-mid-request', + updateSearchParams: true, + }) + logic.mount() + await started + + logic.unmount() + finishRequest({ results: listOfSessionRecordings, has_next: false }) + await new Promise(process.nextTick) + + expect(captureException).not.toHaveBeenCalled() + }) + }) + describe('total filters count', () => { beforeEach(() => { logic = sessionRecordingsPlaylistLogic({ diff --git a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts index 81a2344d6258..059483b57923 100644 --- a/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts +++ b/frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts @@ -993,10 +993,12 @@ export const sessionRecordingsPlaylistLogic = kea