Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native iOS does not report error causes (or multiple errors from an error array) #1956

Open
getsaf opened this issue May 3, 2023 · 2 comments
Labels
backlog We hope to fix this feature/bug in the future bug Confirmed bug

Comments

@getsaf
Copy link

getsaf commented May 3, 2023

Describe the bug

package: @bugsnag/react-native
iOS does not report error causes (It works fine in Android).

Root cause is that the iOS event deserializer is hard-coded to only inspect/deserialize the first error that is reported

Additionally, I found that the bugsnag-cocoa pod also hard-codes attachment of stack traces to the first error in the BugsnagEvent#errors array in the attachCustomStacktrace function which is also called in the event deserializer here (this makes it difficult to provide a full solution without also making changes to bugsnag-cocoa or duplicating some logic from bugsnag-cocoa into the bugsnag-js repo).

- (void)attachCustomStacktrace:(NSArray *)frames withType:(NSString *)type {
    BugsnagError *error = self.errors.firstObject;
    error.stacktrace = [BugsnagStacktrace stacktraceFromJson:frames].trace;
    error.typeString = type;
}

Steps to reproduce

  1. Report an error with a cause property assigned
  2. View the report in the Bugsnag web UI
  3. See the cause is not reported

Environment

  • Bugsnag version: 7.20.2
  • Browser framework version (if any):
    • n/a
  • Server framework version (if any):
    • n/a
  • Device (e.g. iphonex):
    • Any iPhone device

Example code snippet

  const cause = new Error('This is the cause');
  const error = new Error('This is the error', {cause});
  bugsnag.notify(error);
@getsaf
Copy link
Author

getsaf commented May 4, 2023

My current solution is to apply this patch to the 7.20.2 version of the @bugsnag/react-native package:

diff --git a/ios/BugsnagReactNative/BugsnagEventDeserializer.m b/ios/BugsnagReactNative/BugsnagEventDeserializer.m
index 280a788672eba80d678e790b427bc32c83c364e3..88a3c66a65dab7b64575982ebfe325863a7a7fa5 100644
--- a/ios/BugsnagReactNative/BugsnagEventDeserializer.m
+++ b/ios/BugsnagReactNative/BugsnagEventDeserializer.m
@@ -9,6 +9,8 @@
 #import "BugsnagEventDeserializer.h"
 
 #import "BugsnagInternals.h"
+#import "BugsnagError+Private.h"
+#import "BugsnagStacktrace.h"
 
 @implementation BugsnagEventDeserializer
 
@@ -45,25 +47,31 @@ - (BugsnagEvent *)deserializeEvent:(NSDictionary *)payload {
         }
     }
 
-    NSDictionary *error = payload[@"errors"][0];
-
-    if (error != nil) {
-        event.errors[0].errorClass = error[@"errorClass"];
-        event.errors[0].errorMessage = error[@"errorMessage"];
-        NSArray<NSDictionary *> *stacktrace = error[@"stacktrace"];
-        NSArray<NSString *> *nativeStack = payload[@"nativeStack"];
-        if (nativeStack) {
-            NSMutableArray<NSDictionary *> *mixedStack = [NSMutableArray array];
-            for (BugsnagStackframe *frame in [BugsnagStackframe stackframesWithCallStackSymbols:nativeStack]) {
-                frame.type = BugsnagStackframeTypeCocoa;
-                [frame symbolicateIfNeeded];
-                [mixedStack addObject:[frame toDictionary]];
+    // Deserialize *all* errors instead of just the first one
+    // See issue: https://github.com/bugsnag/bugsnag-js/issues/1956
+    [payload[@"errors"] enumerateObjectsUsingBlock:^(NSDictionary *error, NSUInteger idx, BOOL *stop) {
+        if (error != nil) {
+            if (event.errors.count < idx + 1) {
+                event.errors = [event.errors arrayByAddingObject:[BugsnagError new]];
             }
-            [mixedStack addObjectsFromArray:stacktrace];
-            stacktrace = mixedStack;
+            event.errors[idx].errorClass = error[@"errorClass"];
+            event.errors[idx].errorMessage = error[@"errorMessage"];
+            NSArray<NSDictionary *> *stacktrace = error[@"stacktrace"];
+            NSArray<NSString *> *nativeStack = payload[@"nativeStack"];
+            if (nativeStack) {
+                NSMutableArray<NSDictionary *> *mixedStack = [NSMutableArray array];
+                for (BugsnagStackframe *frame in [BugsnagStackframe stackframesWithCallStackSymbols:nativeStack]) {
+                    frame.type = BugsnagStackframeTypeCocoa;
+                    [frame symbolicateIfNeeded];
+                    [mixedStack addObject:[frame toDictionary]];
+                }
+                [mixedStack addObjectsFromArray:stacktrace];
+                stacktrace = mixedStack;
+            }
+            event.errors[idx].stacktrace = [BugsnagStacktrace stacktraceFromJson:stacktrace].trace;
+            event.errors[idx].typeString = @"reactnativejs";
         }
-        [event attachCustomStacktrace:stacktrace withType:@"reactnativejs"];
-    }
+    }];
 
     return event;
 }

@johnkiely1
Copy link
Member

Hi @getsaf, thanks for raising, we will look to get this fixed.

@johnkiely1 johnkiely1 added bug Confirmed bug backlog We hope to fix this feature/bug in the future labels May 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backlog We hope to fix this feature/bug in the future bug Confirmed bug
Projects
None yet
Development

No branches or pull requests

2 participants