What React Native libraries do you use?
Hermes, RN New Architecture, Expo (mobile only), Expo Router
Are you using sentry.io or on-premise?
sentry.io (SaS)
Are you using any other error monitoring solution alongside Sentry?
No
@sentry/react-native SDK Version
8.13.0 → 8.14.0 (regression introduced in 8.14.0)
How does your development environment look like?
- macOS, Android (issue is Android-only; iOS is unaffected)
- React Native 0.85.3, Hermes + New Architecture enabled
- Expo SDK 56, Expo Router
Sentry.init()
Sentry.init({
dsn: "https://...@o...ingest.de.sentry.io/...",
enabled: !__DEV__,
environment: "production",
enableTombstone: true,
integrations: [Sentry.reactNavigationIntegration()],
});
Steps to Reproduce
- Use
@sentry/react-native@8.14.0 on Android.
- Add any breadcrumb from JS — either manually (
Sentry.addBreadcrumb({ message: "test" })) or via auto-instrumentation (navigation, console, etc.). The JS scope syncs it to the native scope via RNSentry.addBreadcrumb.
- Watch Logcat.
Expected Result
The breadcrumb is added to the native Android scope (with its message/category/data/timestamp), so it appears in native/tombstone crash reports. No error logged.
Actual Result
RNSentryBreadcrumb.fromMap logs an error and discards the breadcrumb, returning an empty fallback breadcrumb (only origin = "react-native"). The breadcrumb is lost from the native scope, so native crash reports lose breadcrumb context. Logcat (one entry per breadcrumb):
Failed to deserialize breadcrumb from map.
java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
at io.sentry.util.MapObjectReader.nextStringOrNull(MapObjectReader.java:321)
at io.sentry.util.MapObjectReader.nextDateOrNull(MapObjectReader.java:146)
at io.sentry.Breadcrumb$Deserializer.deserialize(Breadcrumb.java:872)
at io.sentry.react.RNSentryBreadcrumb.fromMap(RNSentryBreadcrumb.java:47)
at io.sentry.react.RNSentryModuleImpl.lambda$addBreadcrumb$5(RNSentryModuleImpl.java:614)
at io.sentry.react.RNSentryModuleImpl$$ExternalSyntheticLambda5.run(D8$$SyntheticClass:0)
at io.sentry.Scopes.configureScope(Scopes.java:753)
at io.sentry.Sentry.configureScope(Sentry.java:1121)
at io.sentry.Sentry.configureScope(Sentry.java:1111)
at io.sentry.react.RNSentryModuleImpl.addBreadcrumb(RNSentryModuleImpl.java:612)
at io.sentry.react.RNSentryModule.addBreadcrumb(RNSentryModule.java:98)
at com.facebook.jni.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:1095)
at android.os.Handler.dispatchMessageImpl(Handler.java:135)
at android.os.Handler.dispatchMessage(Handler.java:125)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.kt:21)
at android.os.Looper.loopOnce(Looper.java:296)
at android.os.Looper.loop(Looper.java:397)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$Companion.startNewBackgroundThread$lambda$0(MessageQueueThreadImpl.kt:152)
at java.lang.Thread.run(Thread.java:1572)
Root cause
The JS SDK (@sentry/core) stamps breadcrumb.timestamp as a number (epoch seconds) and forwards it unchanged to native (scopeSync → wrapper.addBreadcrumb → RNSentry.addBreadcrumb). Over the bridge it becomes a java.lang.Double.
On Android, RNSentryBreadcrumb.fromMap now feeds that map to the wire-format Breadcrumb.Deserializer, which reads timestamp via MapObjectReader.nextDateOrNull → nextStringOrNull and requires an ISO-8601 string, so a Double throws ClassCastException.
This was introduced by #6261 ("Use native SDK deserializers for User and Breadcrumb"), first shipped in 8.14.0. Before that, fromMap parsed fields manually and ignored the numeric timestamp, so it didn't crash. iOS is unaffected because it uses the Cocoa SDK's lenient initWithDictionary:.
Note: User was migrated to the same deserializer in #6261, so its date/numeric fields may have the same issue.
Workaround
Normalize the numeric timestamp to an ISO-8601 string in fromMap before deserializing:
final Map<String, Object> map = toDeepHashMap(from);
final Object timestamp = map.get("timestamp");
if (timestamp instanceof Number) {
map.put("timestamp",
io.sentry.DateUtils.getTimestamp(new java.util.Date((long) (((Number) timestamp).doubleValue() * 1000))));
}
final MapObjectReader reader = new MapObjectReader(map);
What React Native libraries do you use?
Hermes, RN New Architecture, Expo (mobile only), Expo Router
Are you using sentry.io or on-premise?
sentry.io (SaS)
Are you using any other error monitoring solution alongside Sentry?
No
@sentry/react-native SDK Version
8.13.0 → 8.14.0 (regression introduced in 8.14.0)
How does your development environment look like?
Sentry.init()
Steps to Reproduce
@sentry/react-native@8.14.0on Android.Sentry.addBreadcrumb({ message: "test" })) or via auto-instrumentation (navigation, console, etc.). The JS scope syncs it to the native scope viaRNSentry.addBreadcrumb.Expected Result
The breadcrumb is added to the native Android scope (with its message/category/data/timestamp), so it appears in native/tombstone crash reports. No error logged.
Actual Result
RNSentryBreadcrumb.fromMaplogs an error and discards the breadcrumb, returning an empty fallback breadcrumb (onlyorigin = "react-native"). The breadcrumb is lost from the native scope, so native crash reports lose breadcrumb context. Logcat (one entry per breadcrumb):Root cause
The JS SDK (
@sentry/core) stampsbreadcrumb.timestampas a number (epoch seconds) and forwards it unchanged to native (scopeSync→wrapper.addBreadcrumb→RNSentry.addBreadcrumb). Over the bridge it becomes ajava.lang.Double.On Android,
RNSentryBreadcrumb.fromMapnow feeds that map to the wire-formatBreadcrumb.Deserializer, which readstimestampviaMapObjectReader.nextDateOrNull→nextStringOrNulland requires an ISO-8601 string, so aDoublethrowsClassCastException.This was introduced by #6261 ("Use native SDK deserializers for User and Breadcrumb"), first shipped in 8.14.0. Before that,
fromMapparsed fields manually and ignored the numerictimestamp, so it didn't crash. iOS is unaffected because it uses the Cocoa SDK's lenientinitWithDictionary:.Note:
Userwas migrated to the same deserializer in #6261, so its date/numeric fields may have the same issue.Workaround
Normalize the numeric timestamp to an ISO-8601 string in
fromMapbefore deserializing: