getsentry/sentry-electron

navigator.mediaDevices is undefined when i using sentry

0xlau opened this issue ยท 13 comments

Environment

self-hosted (https://develop.sentry.dev/self-hosted/)

Steps to Reproduce

  1. Create Element App
  2. Init Sentry
  3. Call navigator.mediaDevices

Expected Result

navigator.mediaDevices is not undefined.

Actual Result

img_v3_02ck_d8c5883d-61da-4155-847b-0e66bf0362cg

Product Area

Issues

Link

No response

DSN

No response

Version

No response

Auto-routing to @getsentry/product-owners-issues for triage โฒ๏ธ

Hey @0xlau could you share the fullstack trace of the issue? What self-hosted version are you using?

@AbhiPrasad

Sentry version: 23.7.11b5a9d7

https://sentry.lusun.cn/share/issue/99784c50a8fc4b64ad00804fa4f16e7e/

We found the big problem is Sentry.init. When the program reaches this line of code, the navigator will be modified.

Before Sentry init:

img_v3_02ck_8a8c9ad5-941b-4aa5-949f-cc3e7815565g

After Sentry init:

img_v3_02ck_3529d3a3-80db-4a5a-8820-2062bce75a5g

@0xlau are you using the Electron SDK?

From looking at our SDK we don't mutate mediaDevices in anyway:

Electron: https://github.com/search?q=repo%3Agetsentry%2Fsentry-electron+mediaDevices&type=code
JS: https://github.com/search?q=repo%3Agetsentry%2Fsentry-javascript+mediaDevices&type=code

navigator usage: https://github.com/search?q=repo%3Agetsentry%2Fsentry-javascript+navigator&type=code

Could you share your Sentry.init call?

I don't think this is Sentry related, is there another library that could affect navigator?

Yes. We are using the Electron SDK. And we are absolutely sure it's because of Sentry.init, and navigator.mediaDevices is exists before init Sentry. And not only mediaDevices do not exist, all browser api capabilities in navigator no longer exist, including bluetooth, clipboard, etc. ๐Ÿ˜ข

"@sentry/browser": "^8.14.0",
"@sentry/core": "^8.14.0",
"@sentry/electron": "^4.24.0",
"@sentry/react": "^7.116.0",
"@sentry/tracing": "^7.114.0",
"@sentry/vite-plugin": "^2.18.0",

In the Electron main process:

// main.ts
import * as Sentry from '@sentry/electron';

Sentry.init({
   debug: false,
   dsn: "xxxxxx",
   release: `live_desktop@${app.getVersion()}`,
 });

In the Electron renderer process:

import * as Sentry from '@sentry/electron/renderer';
import { init as reactInit } from '@sentry/react';

Sentry.init({
    integrations: [
      Sentry.browserTracingIntegration(),
      Sentry.replayIntegration(),
    ],

    // Set tracesSampleRate to 1.0 to capture 100%
    // of transactions for performance monitoring.
    // We recommend adjusting this value in production
    tracesSampleRate: 1.0,

    // Capture Replay for 10% of all sessions,
    // plus for 100% of sessions with an error
    replaysSessionSampleRate: 0.1,
    replaysOnErrorSampleRate: 1.0,
  },
  reactInit,
);

In Vite Config:

import { sentryVitePlugin } from "@sentry/vite-plugin";
import { version } from '../package.json';

plugins: [
    ...
    sentryVitePlugin({
        org: "yuanze",
        project: "live_desktop",
        url: "https://sentry.lusun.cn/",
        authToken: "xxxx",
        release:{
          name: `live_desktop@${version}`,
        }
      })
]

@0xlau you are using both 8.x and 7.x deps of the JS SDK! Please make sure you are not mixing major versions - either stick to 7.x or upgrade to 8.x overall.

And not only mediaDevices do not exist, all browser api capabilities in navigator no longer exist, including bluetooth, clipboard, etc

I tried reproducing this with my electron apps but no luck (on electron sdk 5.2.0 and js sdk 8.16.0)

maybe try those sdk versions out?

otherwise please share a minimal reproduction of this with a sample electron app so we can test further.

Going to also transfer this to the electron repo! https://github.com/getsentry/sentry-electron

I try to migrate to v8.x. But it still does not work about the missing mediaDevices problem.

    "@sentry/browser": "^8.17.0",
    "@sentry/core": "^8.17.0",
    "@sentry/electron": "^5.2.0",
    "@sentry/react": "^8.17.0",
    "@sentry/vite-plugin": "^2.21.0",

But I found that if I run npm run start in the development environment, navigator.mediaDevices exist, but once I package, navigator doesn't exist. And! If I remove Sentry.init, navigator.mediaDevices will exist whether it is the development environment or after packaging.

@0xlau are you able to reproduce this in a barebones electron app? That would help us understand what is happening, unfortunately even with your versions + sdk setup I was unable to reproduce.

@AbhiPrasad Hey ๐Ÿ‘‹, You can download this project to reproduce this issue.
min-error-sentry-reproduction.zip

Step 1: Npm install

> npm install

Step 2: Run in dev

Run in dev, mediaDevices is available

> npm run start

Step 3: Package

After package and run .app, mediaDevices is not available

> npm run package

Step 4: remove Sentry.init

// remove this in main.ts
// Sentry.init({
//   debug: false,
//   dsn: '__DSN__',
//   release: `test@${app.getVersion()}`,
// });

Step 5: Try package again

Remove Sentry.init and then package and then run .app, mediaDevices is available

> npm run package

I've managed to reproduce the issue with the supplied reproduction and I think it has something to do with custom protocols but I don't know the exact cause yet.

For now you might be able to work aroud this in two different ways:

Load your renderer content using file:// urls rather than a custom protocol

You can load your source files into the renderers via file: URLs and the custom protocol isn't usually required to do this.

Use "Classic" IPC for Sentry communications

If classic IPC cannot be configured (usually due to bundling), the Sentry SDK reverts to using a custom protocol to communicate between renderers and main process. You can force classic IPC by including Sentrys preload hookup code in the top of your preload file:

preload.ts

import '@sentry/electron/preload';

and then disable the Sentry custom protcol setup with the following init option:

import * as Sentry from '@sentry/electron/main';

Sentry.init({
  dsn: '__DSN__',
  ipcMode: Sentry.IPCMode.Classic, // <- this disables the Sentry custom protocol
});

Yep, confirmed that loading the renderer via file URL in production works around the issue:

    const url = pathToFileURL(
      path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`),
    );
    mainWindow.loadURL(url.href);

@timfish @AbhiPrasad

Use "Classic" IPC for Sentry communications

It works fine!
I truly appreciate your timely help.