Skip to content

Commit 518d48a

Browse files
adinauerclaude
andcommitted
fix(core): Report replay sampling callback errors
Record callback_error/replay when beforeErrorSampling throws while the replay controller has an active replay ID. Do not report a loss when no replay is active. Refs GH-6081 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d11680e commit 518d48a

2 files changed

Lines changed: 12 additions & 0 deletions

File tree

‎sentry/src/main/java/io/sentry/SentryClient.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
246246
SentryLevel.ERROR,
247247
"The beforeErrorSampling callback threw an exception. Skipping replay capture.",
248248
e);
249+
if (!SentryId.EMPTY_ID.equals(options.getReplayController().getReplayId())) {
250+
options
251+
.getClientReportRecorder()
252+
.recordLostEvent(DiscardReason.CALLBACK_ERROR, DataCategory.Replay);
253+
}
249254
shouldCaptureReplay = false;
250255
}
251256
}

‎sentry/src/test/java/io/sentry/SentryClientTest.kt‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3964,6 +3964,7 @@ class SentryClientTest {
39643964
@Test
39653965
fun `beforeErrorSampling throwing exception skips replay but still sends errors and crashes`() {
39663966
val replayController = mock<ReplayController>()
3967+
whenever(replayController.replayId).thenReturn(SentryId())
39673968
whenever(replayController.captureReplay(anyOrNull())).thenReturn(SentryId.EMPTY_ID)
39683969
fixture.sentryOptions.setReplayController(replayController)
39693970
val logger = mock<ILogger>()
@@ -4000,11 +4001,16 @@ class SentryClientTest {
40004001
"The beforeErrorSampling callback threw an exception. Skipping replay capture.",
40014002
exception,
40024003
)
4004+
assertClientReport(
4005+
fixture.sentryOptions.clientReportRecorder,
4006+
listOf(DiscardedEvent(DiscardReason.CALLBACK_ERROR.reason, DataCategory.Replay.category, 2)),
4007+
)
40034008
}
40044009

40054010
@Test
40064011
fun `beforeErrorSampling throwing exception does not prevent replay capture for subsequent events`() {
40074012
val replayController = mock<ReplayController>()
4013+
whenever(replayController.replayId).thenReturn(SentryId.EMPTY_ID)
40084014
whenever(replayController.captureReplay(anyOrNull())).thenReturn(SentryId.EMPTY_ID)
40094015
fixture.sentryOptions.setReplayController(replayController)
40104016
var invocations = 0
@@ -4027,6 +4033,7 @@ class SentryClientTest {
40274033
assertThat(invocations).isEqualTo(2)
40284034
verify(replayController).captureReplay(false)
40294035
verify(fixture.transport, times(2)).send(any(), anyOrNull())
4036+
assertClientReport(fixture.sentryOptions.clientReportRecorder, emptyList())
40304037
}
40314038

40324039
@Test

0 commit comments

Comments
 (0)