fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth - #18206

Merged
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam
Nov 14, 2025
Merged

fix(core/vue): Detect and skip normalizing Vue VNode objects with high normalizeDepth#18206
logaretm merged 3 commits into
developfrom
awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam

Conversation

@logaretm

@logaretmlogaretm commented Nov 14, 2025

Copy link
Copy Markdown
Member

Fixes#18203

Problem

When using normalizeDepth: 10 with captureConsoleIntegration enabled, Vue VNodes in console arguments would trigger recursive warning spam. Accessing VNode properties during normalization would trigger Vue's reactive getters, which emit console warnings. These warnings would then be captured and normalized again, creating a recursive loop that could generate hundreds of warnings.

Note that this only happens in dev mode

Solution

Changed isVueViewModel() to detect Vue 3 VNodes (__v_isVNode: true) in addition to Vue 2/3 ViewModels. VNodes are now identified early in the normalization process and stringified as [VueVNode] before their properties are accessed, preventing the recursive warning loop.

Some of the properties on the VNode can also be reactive, so it can incorrectly add those to a watchEffect or a render function reactive dependencies when accessed by the normalizer.

Changes

  • packages/core/src/utils/is.ts: Added __v_isVNode check to isVueViewModel().
  • packages/core/src/utils/normalize.ts: Distinguish VNodes from ViewModels in output ([VueVNode] vs [VueViewModel]).
  • Tests: Added comprehensive unit tests for Vue object detection and integration test that verifies no property access occurs during VNode normalization.

I couldn't reproduce this exactly in a test with a real vue component, but verified it fixes the reproduction example.

The before and after of the captured logs:

Before:

CleanShot 2025-11-14 at 15 46 30

After:

CleanShot 2025-11-14 at 15 45 15

As a Vue developer I don't think the loss of information here would help debug anything.

@linear

linearBot commented Nov 14, 2025

Copy link
Copy Markdown

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser24.63 kB+0.09%+21 B 🔺
@sentry/browser - with treeshaking flags23.13 kB+0.17%+37 B 🔺
@sentry/browser (incl. Tracing)41.28 kB+0.07%+25 B 🔺
@sentry/browser (incl. Tracing, Profiling)45.57 kB+0.08%+33 B 🔺
@sentry/browser (incl. Tracing, Replay)79.73 kB+0.02%+9 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags69.44 kB+0.07%+42 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas)84.43 kB+0.02%+14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback)96.65 kB+0.07%+62 B 🔺
@sentry/browser (incl. Feedback)41.28 kB+0.03%+11 B 🔺
@sentry/browser (incl. sendFeedback)29.29 kB+0.05%+12 B 🔺
@sentry/browser (incl. FeedbackAsync)34.21 kB+0.05%+16 B 🔺
@sentry/react26.32 kB+0.13%+33 B 🔺
@sentry/react (incl. Tracing)43.23 kB+0.02%+5 B 🔺
@sentry/vue29.11 kB+0.11%+30 B 🔺
@sentry/vue (incl. Tracing)43.08 kB+0.12%+49 B 🔺
@sentry/svelte24.65 kB+0.14%+34 B 🔺
CDN Bundle26.95 kB+0.16%+42 B 🔺
CDN Bundle (incl. Tracing)41.83 kB+0.06%+24 B 🔺
CDN Bundle (incl. Tracing, Replay)78.38 kB+0.07%+54 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback)83.84 kB+0.05%+38 B 🔺
CDN Bundle - uncompressed78.92 kB+0.11%+81 B 🔺
CDN Bundle (incl. Tracing) - uncompressed124.08 kB+0.07%+79 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed240.11 kB+0.04%+79 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed252.87 kB+0.04%+79 B 🔺
@sentry/nextjs (client)45.37 kB+0.07%+28 B 🔺
@sentry/sveltekit (client)41.67 kB+0.06%+22 B 🔺
@sentry/node-core50.9 kB+0.08%+40 B 🔺
@sentry/node158.1 kB+0.02%+20 B 🔺
@sentry/node - without tracing92.78 kB+0.05%+41 B 🔺
@sentry/aws-serverless106.53 kB+0.03%+23 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline8,622-11,316-24%
GET With Sentry1,33515%1,654-19%
GET With Sentry (error only)6,08871%7,684-21%
POST Baseline1,169-1,188-2%
POST With Sentry49342%573-14%
POST With Sentry (error only)1,03989%1,040-0%
MYSQL Baseline3,225-4,059-21%
MYSQL With Sentry41713%562-26%
MYSQL With Sentry (error only)2,66483%3,308-19%

View base workflow run

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

return !!(
typeof wat === 'object' &&
wat !== null &&
((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue || (wat as { __v_isVNode?: boolean }).__v_isVNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l/m: Could we add a comment here explaining a little bit what we're doing?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea absolutely

@logaretm
logaretm merged commit fcf35f6 into developNov 14, 2025
195 checks passed
@logaretm
logaretm deleted the awad/js-1162-nuxtvue-high-normalizedepth-causes-warning-spam branch November 14, 2025 20:42
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt/Vue - High normalizeDepth causes warning spam

3 participants

@logaretm@s1gr1d@andreiborza