From 418dde3c3ad7e6d0d0729b5bba25012a02216e4f Mon Sep 17 00:00:00 2001 From: yashrao2607 <140533789+yashrao2607@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:11:48 +0530 Subject: [PATCH 1/2] fix: omit srcdoc attribute when rebuilding iframe elements Setting `srcdoc` on a live iframe makes the browser asynchronously parse and load its own document into the iframe's contentDocument, racing against rrweb's own reconstruction of that iframe's document (built separately from recorded child nodes/mutations). The race can desync the mirror from the live DOM, so a later mutation ends up targeting a node that no longer exists, throwing e.g. "Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'" and taking down the replayer. rrdom's diff-based renderer already special-cases this (see packages/rrdom/src/diff.ts and its CHANGELOG), but the plain browser-DOM rebuild path in rrweb-snapshot did not. Fixes #1736 --- packages/rrweb-snapshot/src/rebuild.ts | 13 ++++++++ packages/rrweb-snapshot/test/rebuild.test.ts | 32 ++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index a6ef85f01b..d0a4ccfdec 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -426,6 +426,19 @@ function buildNode( 'rrweb-original-srcset', n.attributes.srcset as string, ); + } else if (tagName === 'iframe' && name === 'srcdoc') { + /** + * Setting `srcdoc` makes the browser asynchronously parse and load + * its own document into the iframe, racing against (and getting + * clobbered by or clobbering) the document we reconstruct for this + * iframe from its separately-recorded child nodes/mutations. That + * race can leave the mirror out of sync with the live DOM, causing + * later mutations to target nodes that no longer exist (e.g. + * insertBefore throwing "parameter 1 is not of type 'Node'"). + * Omit it; our own reconstruction is the source of truth. + * @see https://github.com/rrweb-io/rrweb/issues/1736 + */ + // ignore } else { node.setAttribute(name, value.toString()); } diff --git a/packages/rrweb-snapshot/test/rebuild.test.ts b/packages/rrweb-snapshot/test/rebuild.test.ts index 27571c164f..129acd4b68 100644 --- a/packages/rrweb-snapshot/test/rebuild.test.ts +++ b/packages/rrweb-snapshot/test/rebuild.test.ts @@ -411,6 +411,38 @@ describe('rebuild', function () { }); }); + describe('iframe srcdoc', function () { + it('omits the srcdoc attribute so the browser does not load its own document into the iframe', function () { + /** + * Setting `srcdoc` on a live iframe makes the browser asynchronously + * parse and load that markup into the iframe's contentDocument, racing + * against rrweb's own reconstruction of the iframe's document (built + * separately from recorded child nodes/mutations). That race can + * desync the mirror from the live DOM, later causing mutations to + * target nodes that no longer exist. + * @see https://github.com/rrweb-io/rrweb/issues/1736 + */ + const node = buildNodeWithSN( + { + id: 1, + tagName: 'iframe', + type: NodeType.Element, + attributes: { + srcdoc: '
hi', + }, + childNodes: [], + }, + { + doc: document, + mirror, + hackCss: false, + cache, + }, + ) as HTMLIFrameElement; + expect(node.hasAttribute('srcdoc')).toBe(false); + }); + }); + describe('rr_width/rr_height', function () { it('rebuild blocked element with correct dimensions', function () { const node = buildNodeWithSN( From fc593244ab52d8b9afba3de41523414975694ba6 Mon Sep 17 00:00:00 2001 From: yashrao2607 <140533789+yashrao2607@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:33:31 +0530 Subject: [PATCH 2/2] chore: add changeset Co-Authored-By: Claude Sonnet 5