Buffered replay can leave an orphaned replay_id link on a replaysOnErrorSampleRate miss
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
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:
tagEventWithReplayId(in thebeforeSendwrapper) links the event to the buffered replay id — no flush.flushReplayForSentEvent(inafterSendEvent, which only fires for events that survive sampling) performs the native flush viaNATIVE.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
- Configure mobile replay in buffer/on-error mode with
replaysOnErrorSampleRatebetween 0 and 1 (e.g.0.5) and errorsampleRate: 1.0. - Trigger errors until one hits the
replaysOnErrorSampleRatemiss branch. - Observe the error event in Sentry carries a
replay_idbut 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
replaysOnErrorSampleRateroll inside it — can only run inafterSendEvent, after the event is already sent. Thereplay_idis gone over the wire and can't be conditionally removed. - The only hook between the gate and transmission is
beforeEnvelope, butcaptureReplay()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
replaysOnErrorSampleRatedecision as a synchronous, side-effect-free query the RN layer can call inbeforeSend(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
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from getsentry/sentry-react-native
-
React-Native Waiting for: Product Owner
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
getsentry/sentry-react-native#6822 · 1 comment ·
Maintainers usually reply within 1 day
-
Bug React-Native Waiting for: Product Owner
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
getsentry/sentry-react-native#6821 · 1 comment ·
Maintainers usually reply within 1 day
-
React-Native Replays Task
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
getsentry/sentry-react-native#6680 · 1 comment ·
Maintainers usually reply within 1 day
-
Improvement React-Native
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
getsentry/sentry-react-native#6143 · 2 comments ·
Maintainers usually reply within 1 day
-
React-Native Task User Feedbacks
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
getsentry/sentry-react-native#5932 · 2 comments ·
Maintainers usually reply within 1 day
All issues in getsentry/sentry-react-native
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
external-issue to-triage
Difficulty 1/5 Under an hour Newbie friendliness 90/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
diegosouzapw/OmniRoute#15401 ·
Maintainers usually reply within 2 days
-
Sign the pledgeOpen
Difficulty 1/5 Under an hour Newbie friendliness 95/100
input-output-hk/devx-updates#163 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
code-yeongyu/oh-my-openagent#9454 ·
Maintainers usually reply within 1 day