From e1bd24db4aa01ce5f3aee4b6a02e982c1f6769b6 Mon Sep 17 00:00:00 2001 From: yunfeng0817 Date: Tue, 27 May 2025 14:06:30 -0700 Subject: [PATCH 1/3] fix: rrweb recorder may throw error when stopping recording after an iframe becomes cross-origin --- packages/rrweb/src/record/index.ts | 13 ++++++++++++- packages/rrweb/test/record.test.ts | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 1308c378a6..7f9fb0b45c 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -617,7 +617,18 @@ function record( ); } return () => { - handlers.forEach((h) => h()); + handlers.forEach((handler) => { + try { + handler(); + } catch (error) { + /** + * This error can occur in a known scenario: + * If an iframe is initially same-origin and observed, but later its src attribute is changed to a cross-origin URL, + * attempting to execute the handler in the stop record function will throw a "cannot access cross-origin frame" error. + * This error is expected and can be safely ignored. + */ + } + }); processedNodeManager.destroy(); recording = false; unregisterErrorHandler(); diff --git a/packages/rrweb/test/record.test.ts b/packages/rrweb/test/record.test.ts index cfba2b46a2..5ff1035975 100644 --- a/packages/rrweb/test/record.test.ts +++ b/packages/rrweb/test/record.test.ts @@ -990,6 +990,21 @@ describe('record', function (this: ISuite) { await assertSnapshot(ctx.events); }); + + it('does not throw error when stopping recording after iframe becomes cross-origin', async () => { + await ctx.page.evaluate(async () => { + const { record } = (window as unknown as IWindow).rrweb; + const stopRecord = record({ + emit: (window as unknown as IWindow).emit, + }); + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + await new Promise((resolve) => setTimeout(resolve, 1000)); + iframe.src = 'https://www.example.com'; // Change the same origin iframe to a cross origin iframe after it's recorded + await new Promise((resolve) => setTimeout(resolve, 1000)); + stopRecord?.(); + }); + }); }); describe('record iframes', function (this: ISuite) { From b9d243eb3a72cb7e94759099b4d7e99898a20ac8 Mon Sep 17 00:00:00 2001 From: yunfeng0817 Date: Tue, 27 May 2025 14:08:43 -0700 Subject: [PATCH 2/3] add change set --- .changeset/nervous-actors-jam.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nervous-actors-jam.md diff --git a/.changeset/nervous-actors-jam.md b/.changeset/nervous-actors-jam.md new file mode 100644 index 0000000000..641eff873d --- /dev/null +++ b/.changeset/nervous-actors-jam.md @@ -0,0 +1,5 @@ +--- +"rrweb": patch +--- + +fix: rrweb recorder may throw error when stopping recording after an iframe becomes cross-origin From 3528d2d0fef356f23d94798d7c838174545c70c9 Mon Sep 17 00:00:00 2001 From: yunfeng0817 Date: Tue, 27 May 2025 14:17:33 -0700 Subject: [PATCH 3/3] add failure message check --- packages/rrweb/src/record/index.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 7f9fb0b45c..dbef08198f 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -621,12 +621,19 @@ function record( try { handler(); } catch (error) { + const msg = String(error).toLowerCase(); /** + * https://github.com/rrweb-io/rrweb/pull/1695 * This error can occur in a known scenario: - * If an iframe is initially same-origin and observed, but later its src attribute is changed to a cross-origin URL, - * attempting to execute the handler in the stop record function will throw a "cannot access cross-origin frame" error. + * If an iframe is initially same-origin and observed, but later its + src attribute is changed to a cross-origin URL, + * attempting to execute the handler in the stop record function will + throw a "cannot access cross-origin frame" error. * This error is expected and can be safely ignored. */ + if (!msg.includes('cross-origin')) { + console.warn(error); + } } }); processedNodeManager.destroy();