Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 82/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- javascript, typescript
- Área
- frontend, performance
Línea de trabajo
Empieza con packages/browser/src/profiling/UIProfiler.ts y compara notifyRootSpanActive() con el listener spanStart de _setupTraceLifecycleListeners(). Comprueba en las pruebas de profiling existentes si se contempla el caso de un span raíz ya activo y no muestreado durante la configuración. Se considera terminado cuando ese caso no inicia el profiler ni envía un fragmento de perfil, mientras que los spans raíz muestreados siguen iniciando el profiling.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Is there an existing issue for this?
- I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- I have reviewed the documentation https://docs.sentry.io/
- I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/browser
SDK Version
@sentry/browser 11.8.0 (also reproduced on 11.4.0; UIProfiler.ts on develop is unchanged as of 2026-10-19)
Framework Version
No response
Link to Sentry event
No response
Reproduction Example/SDK Setup
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: '<dsn>',
integrations: [Sentry.browserTracingIntegration(), Sentry.browserProfilingIntegration()],
tracesSampleRate: 0, // pageload span NOT sampled -> expect NO profiling
profileSessionSampleRate: 1,
profileLifecycle: 'trace',
});
The page is served with Document-Policy: js-profiling.
Steps to Reproduce
- Initialize the SDK with
profileLifecycle: 'trace',profileSessionSampleRate: 1andtracesSampleRate: 0(see SDK setup above). - Load the page. The pageload span is not sampled (
isRecording() === false,traceFlags === 0). - Observe that
new Profiler(...)is called once and aprofile_chunkenvelope is sent when the pageload span ends.
Expected Result
The pageload span is not sampled, so trace lifecycle profiling should not start. This is how root spans started after setup are already handled.
Actual Result
The profiler starts for the unsampled pageload span and a profile_chunk is sent.
I checked this in Chromium with a window.Profiler stub that counts constructor calls and an in-memory transport:
tracesSampleRate: 0,profileSessionSampleRate: 1: profiler started once,profile_chunksenttracesSampleRate: 0,profileSessionSampleRate: 0: profiler not started (control)tracesSampleRate: 1,profileSessionSampleRate: 1: profiler started once,profile_chunkand the pageload span sent (expected)tracesSampleRate: 0,profileSessionSampleRate: 1, pageload instrumentation off, an unsampled root span started afterinit: profiler not started
The last case shows that only the root span that is already active at setup skips the sampling check.
Additional Context
Root cause (source walkthrough)
In packages/browser/src/profiling/integration.ts (develop):
- After
profiler.initialize(client), setup callsprofiler.notifyRootSpanActive(rootSpan)for the active root span. The comment says "If there is an active, sampled root span already, notify the profiler". - Setup calls it again in a
setTimeout(0). This is the path that picks up the pageload span thatbrowserTracingIntegrationstarts inafterAllSetup.
In packages/browser/src/profiling/UIProfiler.ts:
- The
spanStartlistener registered by_setupTraceLifecycleListeners()returns early when!span.isRecording()("Only count sampled root spans"). notifyRootSpanActive()only checks the lifecycle mode and_sessionSampled. It then registers the span and calls_beginProfiling()without checkingrootSpan.isRecording().
So an unsampled root span that is already active at setup starts the profiler. The unsampled span still emits spanEnd, so the profile runs for the length of the pageload.
#17619, which added the trace lifecycle, describes it as "Starts when the first sampled root span starts".
Impact
With profileSessionSampleRate: 1, unsampled pageload spans can still start UI profiling in supported browsers. Reducing tracesSampleRate, even to 0, does not prevent this startup path. This can add unintended profiling overhead and profile usage, without a sampled pageload span to correlate with the resulting chunks.
Related
#22927 was the same kind of gap in the Node trace lifecycle, there for the session sampling decision.
Suggested fix
Return early in notifyRootSpanActive() when !rootSpan.isRecording(), matching the spanStart listener. Happy to open a PR.
- Lenguaje dominante
- TypeScript
- Estrellas
- 8.8k
- Forks
- 1.9k
- Merge medio
- 1 d 11 h
- PR fusionados (30 d)
- 578
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de getsentry/sentry-javascript
-
Hapi: `route.method.toUpperCase is not a function` for routes registered with an array of methodsPosiblemente ocupada @itisrmk la tomó hace 1 día. AbiertoBug Hapi Waiting for: Product Owner
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
getsentry/sentry-javascript#25481 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
node:http client span never ends when the response is destroyed without an error (res.destroy())Posiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. AbiertoBug Node.js Waiting for: Product Owner
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
getsentry/sentry-javascript#25469 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Core Feature: Typescript Meta: Breaking
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
getsentry/sentry-javascript#25286 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 80/100
getsentry/sentry-javascript#24860 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
javascript
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
getsentry/sentry-javascript#24200 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
Todos los issues de getsentry/sentry-javascript
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
ccch1mneyyy/dsh-TUI#1631 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
MiniMax-AI/minimax-code#507 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
-
Transient OAuth login failure persists in getLoginStatus and masks active account in dashboardQuizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abiertoaccount-pool bug gui
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
lidge-jun/opencodex#7378 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
Admin search throws for permissions added through Admin.generalIndexItems('permissions', ...)Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día