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

Issue:
Fix concurrent runs with Sentry Babel transformer
**OS:**
- [ ]  Windows
- [x]  MacOS
- [ ]  Linux

**Platform:**
- [x]  iOS
- [ ]  Android

**SDK:**
- [x]  `@sentry/react-native` (>= 1.0.0)
- [ ]  `react-native-sentry` (<= 0.43.2)

**SDK version:** 5.30.0

**`react-native` version:** 0.72.12

**Are you using Expo?**
- [ ]  Yes
- [x]  No

---
**I have the following issue:**

After integrating `withSentryConfig` in the `metro.config.js`, `annotateReactComponents` is true, we found that when building iOS application through Xcode in debug mode, the `.sentry/. defaultBabelTransformerPath` file was first created and then deleted before the build was completed. **However, when loading the JS Bundle, sentry tried to read the file again and threw an error.**

**Actual result:**

![Image](https://github.com/user-attachments/assets/f5ab5ffc-9e97-4c0d-9f10-d9439b95c2dd)

**Expected result:**

no error



Discussion: if i comment this line. There is no error but the file can not be deleted automatically.
```
function withSentryBabelTransformer(config) {
    const defaultBabelTransformerPath = config.transformer && config.transformer.babelTransformerPath;
    utils_1.logger.debug('Default Babel transformer path from `config.transformer`:', defaultBabelTransformerPath);
    if (!defaultBabelTransformerPath) {
        // This has to be console.warn because the options is enabled but won't be used
        // eslint-disable-next-line no-console
        console.warn('`transformer.babelTransformerPath` is undefined.');
        // eslint-disable-next-line no-console
        console.warn('Sentry Babel transformer cannot be used. Not adding it...');
        return config;
    }
    if (defaultBabelTransformerPath) {
        (0, sentryBabelTransformerUtils_1.saveDefaultBabelTransformerPath)(defaultBabelTransformerPath);
        process.on('exit', () => {
             // comment this line
            // (0, sentryBabelTransformerUtils_1.cleanDefaultBabelTransformerPath)();
        });
    }
    return Object.assign(Object.assign({}, config), { transformer: Object.assign(Object.assign({}, config.transformer), { babelTransformerPath: require.resolve('./sentryBabelTransformer') }) });
}
```
It's my device info.
  Model Name:	MacBook Pro
  Model Identifier:	MacBookPro17,1
  Model Number:	Z11C000BPCH/A
  Chip:	Apple M1
Thanks @feidaZhang for the report, we'll investigate this and follow up here
Hello @feidaZhang 👋 
thank you for your report and the provided information. I debugged the issue with the reported configuration (SDK version: `5.30.0`, react-native version: `0.72.12`) but wasn't able to reproduce.
Could you set the log level to debug:
`export SENTRY_LOG_LEVEL=debug`
and provide us with some extra logs from metro E.g.
```
Sentry Logger [debug]: Default Babel transformer path from `config.transformer`: [TRANSFORMER_PATH]
Sentry Logger [debug]: Saved default Babel transformer path
...
Sentry Logger [debug]: Loading default Babel transformer from [TRANSFORMER_PATH]
Sentry Logger [debug]: Cleaned default Babel transformer path
✨  Done in 7.23s.
```
Do you see the [`Cleaned default Babel transformer path`](https://github.com/getsentry/sentry-react-native/blame/5.30.0/src/js/tools/sentryBabelTransformerUtils.ts#L41) before [metro termination](https://github.com/getsentry/sentry-react-native/blob/5.30.0/src/js/tools/metroconfig.ts#L117)?

We also noticed that the provided screenshot is from the macOS app. Could you confirm if you are building the iOS or macOS app with XCode? Have you made any other customisations in your Xcode setup?
> Hello [@feidaZhang](https://github.com/feidaZhang) 👋 thank you for your report and the provided information. I debugged the issue with the reported configuration (SDK version: `5.30.0`, react-native version: `0.72.12`) but wasn't able to reproduce. Could you set the log level to debug: `export SENTRY_LOG_LEVEL=debug` and provide us with some extra logs from metro E.g.
> 
> ```
> Sentry Logger [debug]: Default Babel transformer path from `config.transformer`: [TRANSFORMER_PATH]
> Sentry Logger [debug]: Saved default Babel transformer path
> ...
> Sentry Logger [debug]: Loading default Babel transformer from [TRANSFORMER_PATH]
> Sentry Logger [debug]: Cleaned default Babel transformer path
> ✨  Done in 7.23s.
> ```
> 
> Do you see the [`Cleaned default Babel transformer path`](https://github.com/getsentry/sentry-react-native/blame/5.30.0/src/js/tools/sentryBabelTransformerUtils.ts#L41) before [metro termination](https://github.com/getsentry/sentry-react-native/blob/5.30.0/src/js/tools/metroconfig.ts#L117)?
> 
> We also noticed that the provided screenshot is from the macOS app. Could you confirm if you are building the iOS or macOS app with XCode? Have you made any other customisations in your Xcode setup?

![Image](https://github.com/user-attachments/assets/052de070-580b-457f-b4e6-cdcddfed4a43)
hi, there are logs i got. I built the application with Xcode, i don't think i made some customisations on setup. One of my colleagues said he has no issue with Apple Intel. **However, it happened on Apple M1.**

If i set `annotateReactComponents:false` on metro.config.js, there is no issue also.
Thank you for sharing the debug logs @feidaZhang 🙇 
My understanding from the last log ([`Cleaned default Babel transformer path`](https://github.com/getsentry/sentry-react-native/blame/5.30.0/src/js/tools/sentryBabelTransformerUtils.ts#L41)) is that that the [Metro server has stopped](https://github.com/getsentry/sentry-react-native/blob/5.30.0/src/js/tools/metroconfig.ts#L117). Could you share more details on how you start the Metro server and if it is running when the error occurs?
@antonis 
yeah, I also noticed [Metro server has stopped](https://github.com/getsentry/sentry-react-native/blob/5.30.0/src/js/tools/metroconfig.ts#L117). 
The metro server is still running and show the errors when it happens.
I tried to start the metro before building using Xcode, I also tried to building the app using Xcode directly.However, I always get the errors.
**Did you build app with Debug executable on Xcode?** I enabled it.
Hi @feidaZhang,
from the Xcode logs I see you are building debug version of your application, during debug builds Metro is by default not executed, as it's expected to load bundle from the running development server.

But in your case metro is executed, which causes deletion of the file and consequently the error in the development server running outside of Xcode.

Have you changed this behaviour intentionally, otherwise it might indicate indicate an error in the build phase.
The current impl of `.sentry/.defaultBabelTransformerPath` doesn't work with multiple parallel build/dev server running.
We can enable multiple parallel build simply just by scoping the `./sentry` using timestamp or unique generated hash.

`./sentry/${timestamp/hash}/.defaultBabelTransformerPath`
I've noticed this directory and file started appearing in the last few weeks. Is it fine to add it to `.gitignore`?
@johnf Yes, can be ignored, it's used for tmp files during the JS bundling process.
Also faced this issue and it's pretty annoying. I just tried to open development build from Expo cli by pressing "i" and it throws an error. It should probably generated in runtime on dev builds if it's missed or if it's missed it shouldn't block app start?
Hi @fediru-gloat, this will be resolved by https://github.com/getsentry/sentry-react-native/pull/4298



Fix (patch):
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 135738a416..6e7c417a42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@
 > make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
 <!-- prettier-ignore-end -->
 
+## Unreleased
+
+### Fixes
+
+- Remove `.sentry` tmp directory and use environmental variables instead to save default Babel transformer path ([#4298](https://github.com/getsentry/sentry-react-native/pull/4298))
+  - This resolves concurrency issues when running multiple bundle processes
+
 ## 6.3.0-beta.1
 
 ### Features
diff --git a/packages/core/src/js/tools/metroconfig.ts b/packages/core/src/js/tools/metroconfig.ts
index 6749c5d988..1acec9d378 100644
--- a/packages/core/src/js/tools/metroconfig.ts
+++ b/packages/core/src/js/tools/metroconfig.ts
@@ -5,7 +5,7 @@ import * as process from 'process';
 import { env } from 'process';
 
 import { enableLogger } from './enableLogger';
-import { cleanDefaultBabelTransformerPath, saveDefaultBabelTransformerPath } from './sentryBabelTransformerUtils';
+import { setSentryDefaultBabelTransformerPathEnv } from './sentryBabelTransformerUtils';
 import { createSentryMetroSerializer, unstable_beforeAssetSerializationPlugin } from './sentryMetroSerializer';
 import type { DefaultConfigOptions } from './vendor/expo/expoconfig';
 export * from './sentryMetroSerializer';
@@ -143,10 +143,7 @@ export function withSentryBabelTransformer(config: MetroConfig): MetroConfig {
   }
 
   if (defaultBabelTransformerPath) {
-    saveDefaultBabelTransformerPath(defaultBabelTransformerPath);
-    process.on('exit', () => {
-      cleanDefaultBabelTransformerPath();
-    });
+    setSentryDefaultBabelTransformerPathEnv(defaultBabelTransformerPath);
   }
 
   return {
diff --git a/packages/core/src/js/tools/sentryBabelTransformerUtils.ts b/packages/core/src/js/tools/sentryBabelTransformerUtils.ts
index dd04d2f67b..29cb715e52 100644
--- a/packages/core/src/js/tools/sentryBabelTransformerUtils.ts
+++ b/packages/core/src/js/tools/sentryBabelTransformerUtils.ts
@@ -1,62 +1,34 @@
 import { logger } from '@sentry/utils';
-import * as fs from 'fs';
-import * as path from 'path';
 import * as process from 'process';
 
 import type { BabelTransformer } from './vendor/metro/metroBabelTransformer';
 
-/**
- * Saves default Babel transformer path to the project root.
- */
-export function saveDefaultBabelTransformerPath(defaultBabelTransformerPath: string): void {
-  try {
-    fs.mkdirSync(path.join(process.cwd(), '.sentry'), { recursive: true });
-    fs.writeFileSync(getDefaultBabelTransformerPath(), defaultBabelTransformerPath);
-    logger.debug('Saved default Babel transformer path');
-  } catch (e) {
-    // eslint-disable-next-line no-console
-    console.error('[Sentry] Failed to save default Babel transformer path:', e);
-  }
-}
+export const SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH = 'SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH';
 
 /**
- * Reads default Babel transformer path from the project root.
+ * Sets default Babel transformer path to the environment variables.
  */
-export function readDefaultBabelTransformerPath(): string | undefined {
-  try {
-    return fs.readFileSync(getDefaultBabelTransformerPath()).toString();
-  } catch (e) {
-    // eslint-disable-next-line no-console
-    console.error('[Sentry] Failed to read default Babel transformer path:', e);
-  }
-  return undefined;
+export function setSentryDefaultBabelTransformerPathEnv(defaultBabelTransformerPath: string): void {
+  process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH] = defaultBabelTransformerPath;
+  logger.debug(`Saved default Babel transformer path ${defaultBabelTransformerPath}`);
 }
 
 /**
- * Cleans default Babel transformer path from the project root.
+ * Reads default Babel transformer path from the environment variables.
  */
-export function cleanDefaultBabelTransformerPath(): void {
-  try {
-    fs.unlinkSync(getDefaultBabelTransformerPath());
-    logger.debug('Cleaned default Babel transformer path');
-  } catch (e) {
-    // We don't want to fail the build if we can't clean the file
-    // eslint-disable-next-line no-console
-    console.error('[Sentry] Failed to clean default Babel transformer path:', e);
-  }
-}
-
-function getDefaultBabelTransformerPath(): string {
-  return path.join(process.cwd(), '.sentry/.defaultBabelTransformerPath');
+export function getSentryDefaultBabelTransformerPathEnv(): string | undefined {
+  return process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH];
 }
 
 /**
  * Loads default Babel transformer from `@react-native/metro-config` -> `@react-native/metro-babel-transformer`.
  */
 export function loadDefaultBabelTransformer(): BabelTransformer {
-  const defaultBabelTransformerPath = readDefaultBabelTransformerPath();
+  const defaultBabelTransformerPath = getSentryDefaultBabelTransformerPathEnv();
   if (!defaultBabelTransformerPath) {
-    throw new Error('Default Babel Transformer Path not found in `.sentry` directory.');
+    throw new Error(
+      `Default Babel transformer path environment variable ${SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH} is not set.`,
+    );
   }
 
   logger.debug(`Loading default Babel transformer from ${defaultBabelTransformerPath}`);