From 43ff622c1579d91223edc73a4b6dff3621096547 Mon Sep 17 00:00:00 2001
From: wizlor-bfw <282750666+wizlor-bfw@users.noreply.github.com>
Date: Thu, 20 Aug 2026 23:07:34 +0000
Subject: [PATCH] fix: keep other img attributes when srcset is backed up
during rebuild
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When rebuilding an
element that has both a `srcset` attribute and
an inlined `rr_dataURL` (used to make locally-recorded images viewable
elsewhere), every attribute on the element was being replaced by a
repeated `rrweb-original-srcset` backup instead of only `srcset` being
backed up. The guard only checked whether the *node* had a `srcset` and
`rr_dataURL`, not whether the attribute currently being applied in the
loop was actually `srcset` — so `class`, `alt`, `sizes`, `decoding`,
`loading`, etc. were all silently dropped on replay.
This is the likely cause of highlight/highlight#4853: recordings taken
with inlineImages enabled (the default on localhost) of responsive
images using `srcset` lose their sizing/styling attributes on replay,
producing a distorted "busted" render.
Fixes highlight/highlight#4853
---
.../fix-img-srcset-attributes-dropped.md | 5 +++
packages/rrweb-snapshot/src/rebuild.ts | 10 ++---
packages/rrweb-snapshot/test/rebuild.test.ts | 41 +++++++++++++++++++
3 files changed, 50 insertions(+), 6 deletions(-)
create mode 100644 .changeset/fix-img-srcset-attributes-dropped.md
diff --git a/.changeset/fix-img-srcset-attributes-dropped.md b/.changeset/fix-img-srcset-attributes-dropped.md
new file mode 100644
index 00000000..1843d6bd
--- /dev/null
+++ b/.changeset/fix-img-srcset-attributes-dropped.md
@@ -0,0 +1,5 @@
+---
+"rrweb-snapshot": patch
+---
+
+fix: rebuilding an `
` with both `srcset` and an inlined `rr_dataURL` was silently dropping every other attribute (`class`, `alt`, `sizes`, `decoding`, `loading`, etc.) instead of only backing up `srcset`, because the guard only checked the node's attributes rather than which attribute was currently being applied
diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts
index 57b5a4d8..d1fd27ab 100644
--- a/packages/rrweb-snapshot/src/rebuild.ts
+++ b/packages/rrweb-snapshot/src/rebuild.ts
@@ -321,14 +321,12 @@ function buildNode(
// ignore
} else if (
tagName === 'img' &&
- n.attributes.srcset &&
+ name === 'srcset' &&
n.attributes.rr_dataURL
) {
- // backup original img srcset
- node.setAttribute(
- 'rrweb-original-srcset',
- n.attributes.srcset as string,
- );
+ // backup original img srcset; every other attribute on this
+ // element still needs to fall through to the `else` branch below
+ node.setAttribute('rrweb-original-srcset', value.toString());
} 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 e72c466f..e06ef3d7 100644
--- a/packages/rrweb-snapshot/test/rebuild.test.ts
+++ b/packages/rrweb-snapshot/test/rebuild.test.ts
@@ -71,6 +71,47 @@ describe('rebuild', function () {
) as HTMLImageElement;
expect(node?.src).toBe(dataURI);
});
+
+ it('should keep other attributes when srcset is also backed up', function () {
+ // Regression test for https://github.com/highlight/highlight/issues/4853:
+ // when an img has both `srcset` and an inlined `rr_dataURL`, every
+ // attribute (not just `srcset`) was being replaced by a repeated
+ // `rrweb-original-srcset` backup instead of being set normally,
+ // because the `name === 'srcset'` check was missing from the branch
+ // condition (it only checked the *node's* attributes, not which
+ // attribute was currently being applied).
+ const dataURI =
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
+ const node = buildNodeWithSN(
+ {
+ id: 1,
+ tagName: 'img',
+ type: NodeType.Element,
+ attributes: {
+ class: 'logo',
+ alt: 'Logo',
+ sizes: '32px',
+ srcset: 'http://example.com/image.png 1x, http://example.com/image2x.png 2x',
+ rr_dataURL: dataURI,
+ src: 'http://example.com/image.png',
+ },
+ childNodes: [],
+ },
+ {
+ doc: document,
+ mirror,
+ hackCss: false,
+ cache,
+ },
+ ) as HTMLImageElement;
+ expect(node?.src).toBe(dataURI);
+ expect(node?.className).toBe('logo');
+ expect(node?.getAttribute('alt')).toBe('Logo');
+ expect(node?.getAttribute('sizes')).toBe('32px');
+ expect(node?.getAttribute('rrweb-original-srcset')).toBe(
+ 'http://example.com/image.png 1x, http://example.com/image2x.png 2x',
+ );
+ });
});
describe('rr_width/rr_height', function () {