Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Buffered replay can leave an orphaned replay_id link on a replaysOnErrorSampleRate miss

Open
#6,696 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
android, ios, react-native, typescript
Domain
mobile-dev

Research direction

Start with packages/core/src/js/replay/mobilereplay.ts, especially tagEventWithReplayId and flushReplayForSentEvent, and trace the beforeSend-to-afterSendEvent pipeline described in the issue. Reproduce with buffered/on-error mobile replay, replaysOnErrorSampleRate below 1, and error sampleRate 1.0. Done means the event is not linked to a replay unless the native SDK will upload that replay, without regressing #6598.

Written by the indexing model from the issue text.

Description

Improvement React-Native
Background

PR #6685 fixed #6598 (a buffered/on-error replay was uploaded for an error later dropped by error sampleRate, orphaning the replay). Since @sentry/core 10.70.0 (getsentry/sentry-javascript#22819) the error sampleRate roll runs after beforeSend, so the fix splits the work:

  1. tagEventWithReplayId (in the beforeSend wrapper) links the event to the buffered replay id — no flush.
  2. flushReplayForSentEvent (in afterSendEvent, which only fires for events that survive sampling) performs the native flush via NATIVE.captureReplay().

This fully fixes the reported case. This issue tracks a narrower residual gap that the split introduces.

The gap

The buffered replay id we tag with in beforeSend is provisional: native assigns it when recording starts, but whether the buffer is actually uploaded depends on the replaysOnErrorSampleRate roll, which happens later inside the async captureReplay() flush.

When an error survives error sampleRate but the replaysOnErrorSampleRate roll misses, the event has already been serialized and sent carrying contexts.replay.replay_id, while no replay is ever uploaded → the event links to a replay that doesn't exist.

Only occurs when replaysOnErrorSampleRate is set below 1.0. Impact is limited to a dangling link (the event's Replay tab resolves to nothing); no replay data or quota is wasted.

Steps to reproduce
  1. Configure mobile replay in buffer/on-error mode with replaysOnErrorSampleRate between 0 and 1 (e.g. 0.5) and error sampleRate: 1.0.
  2. Trigger errors until one hits the replaysOnErrorSampleRate miss branch.
  3. Observe the error event in Sentry carries a replay_id but the referenced replay was never uploaded.
Why it isn't fixable in the JS layer alone

The pipeline order is fixed by @sentry/core:

beforeSend → [error sampleRate gate] → serialize + send → afterSendEvent
 (tag here)                                                (flush here)
  • Tagging must happen before send (the link must be in the outgoing event).
  • Flushing must happen after the sampleRate gate (flushing earlier reintroduces #6598).
  • So the flush — and the replaysOnErrorSampleRate roll inside it — can only run in afterSendEvent, after the event is already sent. The replay_id is gone over the wire and can't be conditionally removed.
  • The only hook between the gate and transmission is beforeEnvelope, but captureReplay() is an async bridge call and can't block the send. A synchronous native flush isn't viable (it does I/O; the old-arch bridge has no sync methods).
Proposed fix (native)

Provide a way for the native SDKs (sentry-cocoa / sentry-android) to decouple the on-error sampling decision from the buffer upload, so RN can reconcile tag and upload. Either:

  • (a) expose the replaysOnErrorSampleRate decision as a synchronous, side-effect-free query the RN layer can call in beforeSend (tag only when it will capture), the decision being cached so the later flush honors the same result; or
  • (b) decouple the decision from the upload so the tag and the eventual upload always agree.
Relationship to #6598

This is the opposite orphaning direction from #6598, and gated by a different sample rate:

#6598 (fixed) #6696 (this issue)
Orphan direction replay with no event event with no replay
Caused by the bug (flush before sampling) the fix's optimistic tagging
Gate sampleRate < 1 replaysOnErrorSampleRate < 1
Severity quota waste + orphaned replay harmless dangling link
Scope broad (any dropped error) narrow (survives sampleRate and replay roll misses)

The fix in #6685 traded a broad, quota-costing orphaned replay for this rare, harmless orphaned link.

References
  • Fix PR: #6685
  • Original issue: #6598
  • Upstream ordering change: getsentry/sentry-javascript#22819
  • Code: packages/core/src/js/replay/mobilereplay.ts (tagEventWithReplayId, flushReplayForSentEvent)
Dominant language
TypeScript
Stars
1.8k
Forks
369
Avg merge
20h 55m
Merged PRs (30d)
105

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from getsentry/sentry-react-native

All issues in getsentry/sentry-react-native

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.