Fix(Replay): dont record ignored/dropped errors#5885
Fix(Replay): dont record ignored/dropped errors#5885lucas-zimerman wants to merge 7 commits intomainfrom
Conversation
… the new workflow Co-authored-by: Claude <noreply@anthropic.com>
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
🤖 This preview updates automatically when you update the PR. |
… into lz/ignore-replay
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Replay bridge errors can drop events
- Added try-catch around processEvent in beforeSend to ensure events are sent without replay data when native bridge calls fail, rather than being dropped.
Or push these changes by commenting:
@cursor push 6824446734
Preview (6824446734)
diff --git a/packages/core/src/js/replay/mobilereplay.ts b/packages/core/src/js/replay/mobilereplay.ts
--- a/packages/core/src/js/replay/mobilereplay.ts
+++ b/packages/core/src/js/replay/mobilereplay.ts
@@ -308,15 +308,21 @@
const clientOptions = client.getOptions();
const originalBeforeSend = clientOptions.beforeSend;
clientOptions.beforeSend = async (event: ErrorEvent, hint: EventHint): Promise<ErrorEvent | null> => {
+ let eventToProcess = event;
if (originalBeforeSend) {
const result = await originalBeforeSend(event, hint);
if (result === null) {
// Event was dropped by user's beforeSend, don't capture replay
return null;
}
- return processEvent(result, hint);
+ eventToProcess = result;
}
- return processEvent(event, hint);
+ try {
+ return await processEvent(eventToProcess, hint);
+ } catch (error) {
+ debug.error(`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} failed to process event, sending without replay data`, error);
+ return eventToProcess;
+ }
};
}
diff --git a/packages/core/test/replay/mobilereplay.test.ts b/packages/core/test/replay/mobilereplay.test.ts
--- a/packages/core/test/replay/mobilereplay.test.ts
+++ b/packages/core/test/replay/mobilereplay.test.ts
@@ -143,6 +143,57 @@
expect(mockCaptureReplay).not.toHaveBeenCalled();
expect(result?.contexts?.replay).toBeUndefined();
});
+
+ it('should return event unchanged when native bridge call fails', async () => {
+ mockCaptureReplay.mockRejectedValue(new Error('Native bridge error'));
+
+ const integration = mobileReplayIntegration();
+ integration.setup?.(mockClient);
+
+ const event = {
+ event_id: 'test-event-id',
+ exception: {
+ values: [{ type: 'Error', value: 'Test error' }],
+ },
+ } as ErrorEvent;
+ const hint: EventHint = {};
+
+ const result = await clientOptions.beforeSend?.(event, hint);
+
+ expect(result).toBeDefined();
+ expect(result).toBe(event);
+ expect(result?.contexts?.replay).toBeUndefined();
+ });
+
+ it('should return modified event from user beforeSend when native bridge fails', async () => {
+ mockCaptureReplay.mockRejectedValue(new Error('Native bridge error'));
+
+ const userBeforeSend = jest
+ .fn<(event: ErrorEvent, hint: EventHint) => ErrorEvent>()
+ .mockImplementation(event => ({
+ ...event,
+ tags: { modified: 'true' },
+ }));
+ clientOptions.beforeSend = userBeforeSend;
+
+ const integration = mobileReplayIntegration();
+ integration.setup?.(mockClient);
+
+ const event = {
+ event_id: 'test-event-id',
+ exception: {
+ values: [{ type: 'Error', value: 'Test error' }],
+ },
+ } as ErrorEvent;
+ const hint: EventHint = {};
+
+ const result = await clientOptions.beforeSend?.(event, hint);
+
+ expect(result).toBeDefined();
+ expect(userBeforeSend).toHaveBeenCalledWith(event, hint);
+ expect(result?.tags).toEqual({ modified: 'true' });
+ expect(result?.contexts?.replay).toBeUndefined();
+ });
});
describe('beforeErrorSampling', () => {This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
| return processEvent(result, hint); | ||
| } | ||
| return processEvent(event, hint); | ||
| }; |
There was a problem hiding this comment.
Replay bridge errors can drop events
High Severity
beforeSend awaits processEvent without guarding failures. If replay bridge calls fail, the wrapped beforeSend rejects and the SDK drops the original event instead of sending it without replay data.
Additional Locations (1)
Triggered by project rule: PR Review Guidelines for Cursor Bot
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.



📢 Type of change
📜 Description
Users wanted to only track errors, but the way
mobileReplaywas set, it triggered replay captured even to dropped errors, since it was doing this on the middle of the event processing workflow, which could lead to dropped events before sending it.💡 Motivation and Context
The fix is a hook into
beforeSend, since it's the last stop before sending an event.Ideally we shold use something like
client.on('beforeBeforeSend...but the client hook was syncronous, which blocks the usage of Native APIs to fetch the replay data to fill into the event's context.This way, when users set to only capture errors, Replay will not send recording data when the only captured events were dropped by IgnoredError/eventProcessor or beforeSend.
💚 How did you test it?
On a device, sample app.
📝 Checklist
sendDefaultPIIis enabled🔮 Next steps
Close #4908