-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Problem
Events are silently lost when an event processor throws an error. This is extremely hard to debug because there's no obvious indication. No events, no log, not even frozen UI, nothing, just HMR breaking, which doesn't seem related at first.
The root cause: when a processor throws, Sentry calls captureException to report it, which runs through the same processors, triggering infinite async recursion. The original event is never sent - it's buried under thousands of processor error events.
We spent significant time debugging why HMR was broken and discovered this.
Reproduction
Minimal repro repo: https://github.com/thomasttvo/sentry-recursion-repro
import * as Sentry from '@sentry/react-native';
Sentry.init({ dsn: '...' });
Sentry.addEventProcessor(async (event) => {
throw new Error('Processor error'); // Throws on ALL events
});
Sentry.captureMessage('Test message'); // This event is LOSTWhat Happens
captureMessage('Test')→ processor throws → original event lost- Sentry catches error →
captureException(processorError)→ processor throws again - Repeat infinitely (700+ times in seconds, async so UI stays responsive)
The original "Test message" event never reaches Sentry. Instead, you get thousands of "Processor error" events (if they even make it through).
Impact
- Silent event loss - Original events never sent, no clear indication why
- Hard to debug - Took significant time to trace the issue
- Infinite async loop - Continuously consumes resources
- HMR breaks - In React Native dev mode, breaks Hot Module Replacement
Root Cause
In @sentry/core client.js:
.then(null, reason => {
if (_isDoNotSendEventError(reason) || _isInternalError(reason)) {
throw reason;
}
this.captureException(reason, { ... }); // Recurses!
throw _makeInternalError(...);
})Each iteration creates a NEW error, so existing guards don't prevent it.
Suggested Fix
Add recursion guard:
let _isProcessingProcessorError = false;
.then(null, reason => {
if (_isProcessingProcessorError) {
console.warn('Event processor error during error handling, breaking recursion');
throw _makeInternalError(...);
}
_isProcessingProcessorError = true;
try {
this.captureException(reason, { ... });
} finally {
_isProcessingProcessorError = false;
}
throw _makeInternalError(...);
})Environment
@sentry/react-nativev7.11.0 (latest; issue exists in@sentry/core)- iOS / React Native / Expo SDK 54
Related Issues
- For error thrown inside EventProcessor the trace is long and the original error is gone #2716 - Acknowledged "it'd cause an infinite loop" but closed without fix
- addEventProcessor silently drops exceptions #2148 - addEventProcessor silently drops exceptions
Metadata
Metadata
Assignees
Labels
Projects
Status