Skip to content

Commit 7df7f30

Browse files
authored
fix(core): Print getTraceMetaTags in 1 line to prevent hydration errors (#22004)
closes #21915 closes [JS-2897](https://linear.app/getsentry/issue/JS-2897) It seems that new lines creating a React hydration error. By removing the newline it works again. IMO it wouldn't matter if there is a newline or not, as in Browsers the markdown is formatted anyways and in code this is anyways the used code. So I don't think there was a benefit of the newline anyways.
1 parent 39d05cd commit 7df7f30

4 files changed

Lines changed: 21 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7-
Work in this release was contributed by @codr. Thank you for your contribution!
7+
Work in this release was contributed by @codr and @zenato. Thank you for your contribution!
88

99
## 10.63.0
1010

packages/core/src/utils/meta.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import { getTraceData } from './traceData';
2323
*
2424
*/
2525
export function getTraceMetaTags(traceData?: SerializedTraceData): string {
26-
return Object.entries(traceData || getTraceData())
27-
.map(([key, value]) => `<meta name="${key}" content="${value}"/>`)
28-
.join('\n');
26+
return (
27+
Object.entries(traceData || getTraceData())
28+
.map(([key, value]) => `<meta name="${key}" content="${value}"/>`)
29+
// Joined without whitespace on purpose: a separator between the tags becomes a text node when
30+
// injected into `<head>`, which breaks React 19 whole-document hydration (#21915).
31+
.join('')
32+
);
2933
}

packages/core/test/lib/utils/meta.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ describe('getTraceMetaTags', () => {
99
baggage: 'sentry-environment=production',
1010
});
1111

12-
expect(getTraceMetaTags())
13-
.toBe(`<meta name="sentry-trace" content="12345678901234567890123456789012-1234567890123456-1"/>
14-
<meta name="baggage" content="sentry-environment=production"/>`);
12+
expect(getTraceMetaTags()).toBe(
13+
'<meta name="sentry-trace" content="12345678901234567890123456789012-1234567890123456-1"/><meta name="baggage" content="sentry-environment=production"/>',
14+
);
1515
});
1616

1717
it('renders just sentry-trace values to stringified Html meta tags', () => {
@@ -39,9 +39,9 @@ describe('getTraceMetaTags', () => {
3939
'sentry-environment=test,sentry-public_key=public12345,sentry-trace_id=ab12345678901234567890123456789012,sentry-sample_rate=0.5',
4040
};
4141

42-
expect(getTraceMetaTags(customTraceData))
43-
.toBe(`<meta name="sentry-trace" content="ab12345678901234567890123456789012-1234567890abcdef-1"/>
44-
<meta name="baggage" content="sentry-environment=test,sentry-public_key=public12345,sentry-trace_id=ab12345678901234567890123456789012,sentry-sample_rate=0.5"/>`);
42+
expect(getTraceMetaTags(customTraceData)).toBe(
43+
'<meta name="sentry-trace" content="ab12345678901234567890123456789012-1234567890abcdef-1"/><meta name="baggage" content="sentry-environment=test,sentry-public_key=public12345,sentry-trace_id=ab12345678901234567890123456789012,sentry-sample_rate=0.5"/>',
44+
);
4545

4646
expect(getTraceDataSpy).not.toHaveBeenCalled();
4747
});

packages/tanstackstart-react/test/server/wrapFetchWithSentry.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ vi.mock('@sentry/node', async importOriginal => {
1717
const getTraceMetaTagsSpy = vi
1818
.fn()
1919
.mockReturnValue(
20-
'<meta name="sentry-trace" content="abc123-def456-1"/>\n<meta name="baggage" content="sentry-trace_id=abc123"/>',
20+
'<meta name="sentry-trace" content="abc123-def456-1"/><meta name="baggage" content="sentry-trace_id=abc123"/>',
2121
);
2222

2323
vi.mock('@sentry/core', async importOriginal => {
@@ -84,6 +84,12 @@ describe('wrapFetchWithSentry', () => {
8484
expect(html).toContain('<meta name="sentry-trace" content="abc123-def456-1"/>');
8585
expect(html).toContain('<meta name="baggage" content="sentry-trace_id=abc123"/>');
8686
expect(html).toContain('<meta charset="utf-8"/>');
87+
88+
// No whitespace text node may appear directly after `<head>` or between the injected tags —
89+
// React 19 whole-document hydration rejects unexpected text nodes in `<head>` (#21915).
90+
expect(html).toContain(
91+
'<head><meta name="sentry-trace" content="abc123-def456-1"/><meta name="baggage" content="sentry-trace_id=abc123"/>',
92+
);
8793
});
8894

8995
it('does not inject meta tags into non-HTML responses', async () => {

0 commit comments

Comments
 (0)