Root cause
Since @sentry/core 10.70.0 (getsentry/sentry-javascript#22819), the error sampleRate roll runs after beforeSend. The mobile-replay on-error flush lives in a beforeSend wrapper (mobilereplay.ts), so it now uploads the buffered replay before the sampling decision. When the error is then dropped by sampleRate, the replay is uploaded with no corresponding error event.
Who is affected
Only the intersection of:
- Buffer / on-error replay (
replaysOnErrorSampleRate)
sampleRate < 1.0 (error events are being sub-sampled)
- A specific error that flushes the buffer and then loses the
sampleRate roll
Full-session replays and default-sampleRate apps are not affected.
Proposed fix
- JS: in
beforeSend, only link the event to the buffered replay id (no upload); defer the native flush to the afterSendEvent client hook, which fires only for events that survive sampling and are actually sent. afterSendEvent already exists in core — no @sentry/core change needed.
- Android: ✅ RN-repo-only. Read the buffered id from
ReplayController.getReplayId() (public sentry-java API).
- iOS: requires an upstream sentry-cocoa change.
PrivateSentrySDKOnly.getReplayId reads the scope (empty while buffering) in all released versions incl. 9.27.0 / main; the buffered sessionReplayId is only reachable via internal APIs (getReplayIntegration, not in the public header). Fix: have getReplayId fall back to the integration's buffered sessionReplayId. iOS then follows with a cocoa bump.
Root cause
Since
@sentry/core10.70.0 (getsentry/sentry-javascript#22819), the errorsampleRateroll runs afterbeforeSend. The mobile-replay on-error flush lives in abeforeSendwrapper (mobilereplay.ts), so it now uploads the buffered replay before the sampling decision. When the error is then dropped bysampleRate, the replay is uploaded with no corresponding error event.Who is affected
Only the intersection of:
replaysOnErrorSampleRate)sampleRate < 1.0(error events are being sub-sampled)sampleRaterollFull-session replays and default-
sampleRateapps are not affected.Proposed fix
beforeSend, only link the event to the buffered replay id (no upload); defer the native flush to theafterSendEventclient hook, which fires only for events that survive sampling and are actually sent.afterSendEventalready exists in core — no@sentry/corechange needed.ReplayController.getReplayId()(public sentry-java API).PrivateSentrySDKOnly.getReplayIdreads the scope (empty while buffering) in all released versions incl. 9.27.0 /main; the bufferedsessionReplayIdis only reachable via internal APIs (getReplayIntegration, not in the public header). Fix: havegetReplayIdfall back to the integration's bufferedsessionReplayId. iOS then follows with a cocoa bump.