Skip to content

browser-utils: onLCP's handleEntries has no null-check on entry, unlike upstream web-vitals — throws "Cannot read properties of undefined (reading 'startTime')" #24278

Description

@stea4lth

Environment

  • @sentry/nextjs 10.57.0 (also confirmed still present in @sentry-internal/browser-utils at the latest release, 10.74.0)
  • Next.js 16.2.12, Turbopack build
  • Public production page, real-user traffic (not reproduced synthetically)

What happened

A visitor's browser threw an uncaught error on a public page load:

Uncaught TypeError: Cannot read properties of undefined (reading 'startTime')
    at et.reportAllChanges (<anonymous>:2:19429)
    at <anonymous>:2:13070
    at <anonymous>:2:331
    at d (<anonymous>:2:6141)
    at <anonymous>:2:6326
    at <anonymous>:2:2895
    at n.timeout (<anonymous>:2:5652)

tracesSampleRate: 0 was set, but the SDK still registers browserTracingIntegration, which auto-adds webVitalsIntegration, which observes LCP via the vendored web-vitals fork in @sentry-internal/browser-utils.

Root cause (verified against source, not just the bundle)

packages/browser-utils/src/metrics/web-vitals/getLCP.ts, onLCP's handleEntries:

https://github.com/getsentry/sentry-javascript/blob/10.57.0/packages/browser-utils/src/metrics/web-vitals/getLCP.ts#L52-L67

for (const entry of entries) {
  lcpEntryManager._processEntry(entry);

  if (entry.startTime < visibilityWatcher.firstHiddenTime) {

entry is read from the entries array with no check that it's actually defined. If any element of that array is falsy, this throws exactly the error above.

I checked this three ways before filing:

  1. The installed @sentry-internal/browser-utils@10.57.0 bundle in node_modules — same unguarded code, matches the production stack trace.
  2. Sentry's own source at the 10.57.0 tag (linked above) — identical.
  3. Sentry's own source at the latest release (10.74.0) — same unguarded loop, so this isn't already fixed:
    https://github.com/getsentry/sentry-javascript/blob/10.74.0/packages/browser-utils/src/metrics/web-vitals/getLCP.ts#L60-L66

Compared to upstream web-vitals

packages/browser-utils/src/metrics/web-vitals/README.md documents this as a manually-vendored, frozen fork of GoogleChrome/web-vitals v5.1.0 (commit e22d23b), not auto-synced. Current upstream web-vitals (src/onLCP.ts) has since added a guard in the same loop:

for (const entry of entries) {
  if (!entry) continue;
  ...

(Added in GoogleChrome/web-vitals#308, "Add Soft Navigation support" — so it's possible the original motivation was soft-nav-specific, and I can't say for certain that's the same mechanism producing an undefined entry in a non-soft-nav SDK build. But the defect itself — no defensive check on an array element before dereferencing it — is real and present in Sentry's fork regardless of why upstream added the check.)

What I could not confirm

I don't have a minimal reproduction for why entries contains a falsy element in this case — only the real-user stack trace and the confirmed absence of a guard that would prevent the crash if it does. Happy to share more from our Sentry project if that helps narrow it down.

Suggested fix

Add the same defensive check Sentry already has to pull in elsewhere in this vendored copy — if (!entry) continue; at the top of the for loop in handleEntries — cheap, matches upstream's current shape, and turns a hard crash into a silent skip for whatever produces the falsy element.

Workaround in place on our end

We filter browserTracingIntegration/webVitalsIntegration out of integrations entirely (since we don't use tracing — tracesSampleRate: 0), which sidesteps this rather than fixing it. Happy to share that filter if useful context, but wanted to report the underlying null-safety gap rather than just work around it silently.

Activity

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

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions