Skip to content

Vue tracing mixin schedules a 2-second timer per component, even with trackComponents: false #24858

Closed

Description

@samiashi

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nuxt (the code in question is in @sentry/vue)

SDK Version

10.73.0

Framework Version

Vue 3.5.42, Nuxt 4.5.2

Link to Sentry event

No response

Reproduction Example/SDK Setup

Default Vue integration, tracing on, component tracking left off:

import { createApp, h } from "vue";
import * as Sentry from "@sentry/vue";

const Leaf = { render: () => h("span", "x") };
const App = {
  render: () => h("div", Array.from({ length: 1000 }, () => h(Leaf))),
};

const app = createApp(App);
Sentry.init({ app, dsn: "<dsn>", tracesSampleRate: 1.0 });

let timers = 0;
const setTimeoutOriginal = window.setTimeout;
window.setTimeout = (handler, delay, ...args) => {
  if (delay === 2000) timers += 1;
  return setTimeoutOriginal(handler, delay, ...args);
};

app.mount("#app");
console.log(timers); // 2003

Steps to Reproduce

  1. Enable tracing in a Vue 3 app (any tracesSampleRate) and leave trackComponents at its default of false.
  2. Render a view with many components, for example a table with a component per cell.
  3. Count setTimeout and clearTimeout calls during the mount.

Expected Result

With component tracking off, render work should cost the SDK roughly the same no matter how many components mount: one debounce timer for the root Application Render span, pushed back while render activity continues.

Actual Result

Every untracked component calls maybeEndRootComponentSpan(this, …) from both of its mount hooks, and the timer handle is stored on that component (vm.$_sentryRootComponentSpanTimer) rather than on the root. The debounce therefore never coalesces across components:

Components mounted setTimeout(…, 2000) calls clearTimeout calls
100 203 102
1,000 2,003 1,002

That leaves one pending timer per component. All of them fire about two seconds after the render, and each is a no-op once the first has ended the root span.

On our heaviest page, a review table that mounts thousands of components, this came to about 10,000 timer calls and roughly 60 ms of main-thread time in a Chrome CPU profile, plus the burst of callbacks two seconds later, which can land on the user's first interaction. trackComponents and hooks don't avoid it: the !shouldTrack branch still calls maybeEndRootComponentSpan, and DEFAULT_HOOKS is always included.

Additional Context

Keeping a single timer on $root would make this constant per render, for example:

  • store the latest activity timestamp on vm.$root on every hook (a property write);
  • start one timer on the root if none is pending;
  • when it fires, end the span at the stored timestamp if no activity happened within timeout, otherwise re-arm it for the remaining time.

That would also end Application Render at the last render activity. Today, because each component keeps its own timer, it looks like whichever timer fires first ends the root span with its component's timestamp, which can be before the render finished.

Possibly related: #23375, about the Vue integration's reliance on app.mixin() under Nuxt 5. createTracingMixins on develop still has the per-component timer.

Activity

  1. linear-code commented on Sep 30, 2026

    @linear-code
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Sep 30, 2026
  3. self-assigned this
    on Sep 30, 2026
  4. samiashi commented on Sep 30, 2026

    @samiashi
    Author

    Hi @s1gr1d, I noticed you picked this up. I've already opened a fix in #24864. Happy to adjust it to whatever approach you had in mind, or to hand it over entirely.

  5. s1gr1d commented on Sep 30, 2026

    @s1gr1d
    Member

    Oh, I only noticed your PR now 😬

  6. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Sep 30, 2026
  7. samiashi commented on Sep 30, 2026

    @samiashi
    Author

    Oh, I only noticed your PR now 😬

    No worries at all! Thanks for picking this up so quickly

  8. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Sep 30, 2026
  9. added a commit that references this issue on Sep 30, 2026
    9f99ac6
  10. github-actions commented on Oct 1, 2026

    @github-actions
    Contributor

    A PR closing this issue has just been released 🚀

    This issue was referenced by PR #24868, which was included in the 11.2.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions