Repository: getsentry/sentry-react-native (TypeScript)

Issue:
The `abs_path` of the stack frame is `index.android.bundle` which is not a valid URL
**OS:**
- [ ]  Windows
- [ ]  MacOS
- [x]  Linux

**Platform:**
- [ ]  iOS
- [x]  Android

**SDK:**
- [x]  `@sentry/react-native` (>= 1.0.0)
- [ ]  `react-native-sentry` (<= 0.43.2)

**SDK version:** 5.1.0

**`react-native` version:** 0.71.4

**Are you using Expo?**
- [ ]  Yes
- [x]  No

**Are you using sentry.io or on-premise?**
- [x]  sentry.io (SaaS)
- [ ]  on-premise

**If you are using sentry.io, please post a link to your issue so we can take a look:**

[Link to issue](https://dr-pogodin-studio.sentry.io/issues/3988722801)

**Configuration:**

(`@sentry/react-native`)
```
Sentry.init({
  dsn: 'A_VALID_DSN_OF_SENTRY_PROJECT',
  release: 'A_VALID_RELEASE',
  dist: 'A_VALID_DIST',
});
```

---
**I have following issue:**

My React Native (v0.70.4) app project was correctly set up and working with Sentry (v4.8.0), in particular the source map upload and resolution used to work fine. Yesterday I updated my app, among other stuff I have upgraded `@sentry/react-native` v4.8.0 &rArr; v.5.1.0; and `react-native` v.0.70.4 &rArr; v0.71.4, without touching anything else related to the Sentry setup. After this the source map  resolution in new error events fails with the message:

> **Invalid Absolute Path URL**
> The `abs_path` of the stack frame is `index.android.bundle` which is not a valid URL.

I checked that my build artifacts are still correctly uploaded, and look no different than before. The `abs_path` values in the event JSON have changed though:
- For the new events, received after the upgrade, I see the values like `"abs_path":"index.android.bundle"`
- In events received before the upgrade these values were like `"abs_path":"app:///index.android.bundle"`.

Thus, in my current understanding, it is caused either by a bug or a feature in the latest releases of `@sentry/react-native`. I wasn't able to find any relevant info in the Sentry migration guide for v5, or in the trouble-shooring, general setup instructions, existing issues in the repo; thus asking for help to further troubleshoot and fix it.


Discussion: I'm seeing this as well in my react native android build.
`@sentry/react-native`: `^5.1.0`
`react-native`: `0.69.7`

hermes has also been enabled by default, which might be a factor. 

My attempts at manually uploading and automatically uploading both have led to the same error.  
Same here.
`@sentry/react-native: 5.1.0`
`react-native: 0.71.4`

It was previously working while I was on `@sentry/react-native: 4.15.0`.
Take a look at https://docs.sentry.io/platforms/react-native/troubleshooting/#source-maps-with-hermes
Depending on the version, a few things changed on the RN - Hermes side, that might help if you are manually uploading source maps.
@marandaneto I don't upload source maps manually, I rely on the standard Sentry Gradle plugin on Android, and I was using Hermes before with no problems with source maps.
I have the same issue. I am using the gradle plugin to upload my source maps. Is there a reason that doesn't work with v5 anymore? Why would we be using the gradle plugin at all then? That is especially relevant because Hermes is now the recommended standard by the RN team.
I'm not aware that it stopped working, @krystofwoldrich can you double check?
v5 also broke ios for me. Switching back to v4 solved that issue
Thank you for the info, I'm checking it now.
Same for me with @sentry/react-native: 5.1.0 on React Native 0.67.3.
When revert back to @sentry/react-native: 5.0.0 everything is OK.
Hi same issue there, was working even with hermes activated, only upgrade of sentry/react-native.
Having the same issue with `@sentry/react-native@5.1.0` on:
- Sentry On-Premise
- react-native 0.70.6
- Android

When reverted back to `@sentry/react-native@5.0.0` the issue is gone.

We are working on a permanent fix but for now, everyone who is using `5.1.0`. Can use this workaround.


```js
import {
  defaultStackParser,
} from '@sentry/react';

const defaultReactNativeStackParser = (stack: string, skipFirst?: number) => {
  const frames = defaultStackParser(stack, skipFirst);

  return frames.map(frame => {
    delete frame.abs_path;
    return frame;
  });
}

Sentry.init({
  stackParser: defaultReactNativeStackParser
});
```



Fix (patch):
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a8bd5c53b..68301d0058 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
 
 ## Unreleased
 
+### Fixes
+
+- Remove non URL `frame.abs_path` which was causing source maps to fail ([#2891](https://github.com/getsentry/sentry-react-native/pull/2891))
+
 ### Dependencies
 
 - Bump Cocoa SDK from v8.2.0 to v8.3.0 ([#2876](https://github.com/getsentry/sentry-react-native/pull/2876))
diff --git a/src/js/integrations/rewriteframes.ts b/src/js/integrations/rewriteframes.ts
new file mode 100644
index 0000000000..47c3342b74
--- /dev/null
+++ b/src/js/integrations/rewriteframes.ts
@@ -0,0 +1,34 @@
+import { RewriteFrames } from '@sentry/integrations';
+import type { StackFrame } from '@sentry/types';
+
+/**
+ * Creates React Native default rewrite frames integration
+ * which appends app:// to the beginning of the filename
+ * and removes file://, 'address at' prefixes and CodePush postfix.
+ */
+export function createReactNativeRewriteFrames(): RewriteFrames {
+  return new RewriteFrames({
+    iteratee: (frame: StackFrame) => {
+      if (frame.filename) {
+        frame.filename = frame.filename
+          .replace(/^file:\/\//, '')
+          .replace(/^address at /, '')
+          .replace(/^.*\/[^.]+(\.app|CodePush|.*(?=\/))/, '');
+
+        if (
+          frame.filename !== '[native code]' &&
+          frame.filename !== 'native'
+        ) {
+          const appPrefix = 'app://';
+          // We always want to have a triple slash
+          frame.filename =
+            frame.filename.indexOf('/') === 0
+              ? `${appPrefix}${frame.filename}`
+              : `${appPrefix}/${frame.filename}`;
+        }
+        delete frame.abs_path;
+      }
+      return frame;
+    },
+  });
+}
diff --git a/src/js/sdk.tsx b/src/js/sdk.tsx
index 41234e9110..231073e2a5 100644
--- a/src/js/sdk.tsx
+++ b/src/js/sdk.tsx
@@ -1,13 +1,12 @@
 import type { Scope } from '@sentry/core';
 import { getIntegrationsToSetup, Hub, initAndBind, makeMain, setExtra } from '@sentry/core';
-import { RewriteFrames } from '@sentry/integrations';
 import {
   defaultIntegrations as reactDefaultIntegrations,
   defaultStackParser,
   getCurrentHub,
   makeFetchTransport,
 } from '@sentry/react';
-import type { Integration, StackFrame, UserFeedback } from '@sentry/types';
+import type { Integration, UserFeedback } from '@sentry/types';
 import { logger, stackParserFromStackParserOptions } from '@sentry/utils';
 import * as React from 'react';
 
@@ -22,6 +21,7 @@ import {
   Release,
   SdkInfo,
 } from './integrations';
+import { createReactNativeRewriteFrames } from './integrations/rewriteframes';
 import { Screenshot } from './integrations/screenshot';
 import { ViewHierarchy } from './integrations/viewhierarchy';
 import type { ReactNativeClientOptions, ReactNativeOptions, ReactNativeWrapperOptions } from './options';
@@ -107,29 +107,7 @@ export function init(passedOptions: ReactNativeOptions): void {
       defaultIntegrations.push(new DebugSymbolicator());
     }
 
-    defaultIntegrations.push(new RewriteFrames({
-      iteratee: (frame: StackFrame) => {
-        if (frame.filename) {
-          frame.filename = frame.filename
-            .replace(/^file:\/\//, '')
-            .replace(/^address at /, '')
-            .replace(/^.*\/[^.]+(\.app|CodePush|.*(?=\/))/, '');
-
-          if (
-            frame.filename !== '[native code]' &&
-            frame.filename !== 'native'
-          ) {
-            const appPrefix = 'app://';
-            // We always want to have a triple slash
-            frame.filename =
-              frame.filename.indexOf('/') === 0
-                ? `${appPrefix}${frame.filename}`
-                : `${appPrefix}/${frame.filename}`;
-          }
-        }
-        return frame;
-      },
-    }));
+    defaultIntegrations.push(createReactNativeRewriteFrames());
     if (options.enableNative) {
       defaultIntegrations.push(new DeviceContext());
     }