Repository navigation
fix(desktop): register Sentry IPC protocol for custom session partition - #883
Conversation
📝 WalkthroughWalkthroughSentry init was moved from top-level startup to run after Changes
Sequence Diagram(s)sequenceDiagram
participant App as Electron App (index.ts)
participant Second as Second-instance handler
participant Sentry as Sentry module (lib/sentry.ts)
participant Session as Electron Session
participant Preload as Preload (renderer)
App->>Second: second-instance startup event
Second->>App: await app.whenReady()
Second->>Sentry: call initSentry()
Sentry->>Session: access defaultSession & fromPartition("persist:superset")
Sentry->>Sentry: Sentry.init(..., ipcMode: IPCMode.Classic)
Sentry-->>Second: init complete
Second->>App: continue startup (create windows / load preload)
Preload->>Sentry: preload registers renderer IPC (Classic)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/desktop/src/main/lib/sentry.ts`:
- Around line 7-12: Add dotenv loading at the very top of the app entrypoint
before any other imports so runtime .env variables are available when env.main
is imported and initSentry() is called; specifically, in the entrypoint file
(the top of index.ts) call config({ path: resolve(... to the repo .env),
override: true }) from dotenv/ node:path before importing env.main or
initSentry, ensuring SENTRY_DSN_DESKTOP and other env vars are populated at
runtime.
🧹 Nitpick comments (1)
apps/desktop/src/main/lib/sentry.ts (1)
21-29: Extract hardcoded Sentry settings to constants.Keeps configuration centralized and self-documenting (traces sample rate + partition string).
♻️ Proposed refactor
import { env } from "../env.main"; +const TRACE_SAMPLE_RATE = 0.1; +const SENTRY_SESSION_PARTITION = "persist:superset"; + let sentryInitialized = false; @@ Sentry.init({ dsn: env.SENTRY_DSN_DESKTOP, environment: env.NODE_ENV, - tracesSampleRate: 0.1, + tracesSampleRate: TRACE_SAMPLE_RATE, sendDefaultPii: false, // Register IPC protocol for custom session partition used by renderer // This callback is invoked lazily after app.whenReady() getSessions: () => [ session.defaultSession, - session.fromPartition("persist:superset"), + session.fromPartition(SENTRY_SESSION_PARTITION), ], });
| /** | ||
| * Initialize Sentry in the main process. | ||
| * MUST be called before app.whenReady() for scheme registration to work. | ||
| * The getSessions callback is called lazily after app ready. | ||
| */ | ||
| export function initSentry(): void { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the first 120 lines of index.ts to see env loading and import order
sed -n '1,120p' apps/desktop/src/main/index.ts
# Check where initSentry is called
rg -nP '\binitSentry\s*\(' apps/desktop/src/main/index.ts
# Check if initSentry is awaited anywhere
rg -nP '\bawait\s+initSentry\b' apps/desktop/src/main/index.ts
# Check for .then() chains on initSentry
rg -nP 'initSentry\s*\(\s*\)' apps/desktop/src/main/index.tsRepository: superset-sh/superset
Length of output: 3442
🏁 Script executed:
#!/bin/bash
# Check the absolute first lines for env loading
head -20 apps/desktop/src/main/index.ts
# Search for dotenv or env loading anywhere in the file
rg -n 'dotenv|process\.env|loadEnv' apps/desktop/src/main/index.ts | head -20Repository: superset-sh/superset
Length of output: 932
🏁 Script executed:
#!/bin/bash
# Check sentry.ts for env loading
rg -n 'dotenv|loadEnv|process\.env' apps/desktop/src/main/lib/sentry.ts
# Check electron.vite.config.ts
rg -n 'dotenv|loadEnv|process\.env' apps/desktop/electron.vite.config.ts | head -20
# Look for any .env file references or dotenv imports in apps/desktop
rg -r 'dotenv' apps/desktop --type ts --type js | head -20Repository: superset-sh/superset
Length of output: 2543
🏁 Script executed:
#!/bin/bash
# Check first 20 lines of electron.vite.config.ts
sed -n '1,20p' apps/desktop/electron.vite.config.tsRepository: superset-sh/superset
Length of output: 777
🏁 Script executed:
#!/bin/bash
# Search for config() call with override in both files
rg -n 'config\s*\(' apps/desktop/electron.vite.config.ts | grep -i override
rg -n 'config\s*\(' apps/desktop/src/main/index.ts
# Also search without override filter to see all config calls
rg -n 'config\s*\(' apps/desktop/electron.vite.config.tsRepository: superset-sh/superset
Length of output: 205
🏁 Script executed:
#!/bin/bash
# Check sentry.ts for environment variable usage
cat -n apps/desktop/src/main/lib/sentry.tsRepository: superset-sh/superset
Length of output: 1373
🏁 Script executed:
#!/bin/bash
# Check the env.main file
find apps/desktop -name "env.main*" -type f
# List the structure
ls -la apps/desktop/src/main/Repository: superset-sh/superset
Length of output: 508
🏁 Script executed:
#!/bin/bash
# Check env.main.ts
cat -n apps/desktop/src/main/env.main.tsRepository: superset-sh/superset
Length of output: 2032
🏁 Script executed:
#!/bin/bash
# Check if any .env file is present in desktop root
ls -la apps/desktop/.env* 2>/dev/null || echo "No .env files in apps/desktop root"
# Check package.json scripts to see if env is loaded before app start
jq '.scripts' apps/desktop/package.json 2>/dev/null | grep -i 'dev\|start' || echo "Checking full package.json"
# Look for any other dotenv imports/calls in src/main
rg -n 'dotenv|loadEnv' apps/desktop/src/main/ --type tsRepository: superset-sh/superset
Length of output: 411
Add dotenv.config() with override to load .env variables before any imports in src/main/index.ts.
The environment variables must be loaded at runtime in the electron app entry point before initSentry() is imported. Currently, env.main tries to read process.env variables (including SENTRY_DSN_DESKTOP) but they are not available because .env is only loaded during the vite build configuration, not at app runtime. Add the following at the very top of apps/desktop/src/main/index.ts before any imports:
import { config } from "dotenv";
import { resolve } from "node:path";
config({ path: resolve(__dirname, "../../.env"), override: true });This aligns with the requirement that initSentry() runs before app.whenReady() and ensures environment variables are accessible when env.main is imported.
🤖 Prompt for AI Agents
In `@apps/desktop/src/main/lib/sentry.ts` around lines 7 - 12, Add dotenv loading
at the very top of the app entrypoint before any other imports so runtime .env
variables are available when env.main is imported and initSentry() is called;
specifically, in the entrypoint file (the top of index.ts) call config({ path:
resolve(... to the repo .env), override: true }) from dotenv/ node:path before
importing env.main or initSentry, ensuring SENTRY_DSN_DESKTOP and other env vars
are populated at runtime.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@apps/desktop/src/main/lib/sentry.ts`:
- Around line 12-33: Hardcoded partition string "persist:superset" is
duplicated; extract it as an exported constant named SUPERSET_PARTITION in the
shared constants module, then replace the literal in initSentry's getSessions
(session.fromPartition(...)) with session.fromPartition(SUPERSET_PARTITION) and
replace the literal used for the BrowserWindow partition setting in the windows
main module with SUPERSET_PARTITION; add the appropriate import of
SUPERSET_PARTITION where initSentry (getSessions) and the window creation code
reference the partition.
🧹 Nitpick comments (1)
apps/desktop/src/main/lib/sentry.ts (1)
29-31: Extract the session partition id to a named constant.This avoids drift if the partition id is reused elsewhere (e.g., BrowserWindow configuration). As per coding guidelines, extract hardcoded values to named constants.
♻️ Suggested refactor
- session.fromPartition("persist:superset"), + session.fromPartition(SUPSERSET_SESSION_PARTITION),const SUPSERSET_SESSION_PARTITION = "persist:superset";
| export function initSentry(): void { | ||
| if (sentryInitialized) return; | ||
|
|
||
| if (!env.SENTRY_DSN_DESKTOP || env.NODE_ENV !== "production") { | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| // Dynamic import to avoid bundler issues | ||
| const Sentry = await import("@sentry/electron/main"); | ||
|
|
||
| Sentry.init({ | ||
| dsn: env.SENTRY_DSN_DESKTOP, | ||
| environment: env.NODE_ENV, | ||
| tracesSampleRate: 0.1, | ||
| sendDefaultPii: false, | ||
| // Use Classic IPC mode instead of Protocol to avoid timing issues | ||
| // Protocol mode requires init before app ready, which is unreliable with bundlers | ||
| ipcMode: IPCMode.Classic, | ||
| // Include custom session partition used by our BrowserWindow | ||
| getSessions: () => [ | ||
| session.defaultSession, | ||
| session.fromPartition("persist:superset"), | ||
| ], | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/desktop/src/main/lib/sentry.tsRepository: superset-sh/superset
Length of output: 1504
🏁 Script executed:
ls -la apps/desktop/src/shared/ | head -20Repository: superset-sh/superset
Length of output: 1178
🏁 Script executed:
cat apps/desktop/tsconfig.json 2>/dev/null || cat apps/desktop/tsconfig.base.json 2>/dev/null || cat tsconfig.json | head -50Repository: superset-sh/superset
Length of output: 440
🌐 Web query:
@sentry/electron v7.5.0 IPCMode.Classic getSessions custom partition electron best practices
💡 Result:
Below are concise best practices for using @sentry/electron v7.5.0 with IPCMode.Classic and apps that use custom Electron sessions/partitions.
Key facts
- The SDK option getSessions should return an array of Electron Session objects; default is [session.defaultSession]. [1]
- IPCMode.Classic uses Electron IPC to forward events/scopes between renderers and the main process. [1]
- Electron sessions are created/obtained with session.fromPartition(partition) and BrowserWindow can be created with a partition option (use "persist:name" for persistent sessions). [2][3]
Practical best practices
- Provide getSessions that returns every session you want Sentry to listen/attach to (including session.fromPartition('persist:my-part')) so renderer processes using custom partitions are covered:
- Example: getSessions: () => [ session.defaultSession, session.fromPartition('persist:my-part') ]. [1][2]
- Call Sentry.init (main) and set getSessions early in main (before creating BrowserWindow instances using those partitions) so the SDK can configure IPC/handlers for those sessions. [1][2]
- Use persistent partitions ("persist:...") for windows that need persistent cookies/storage and ensure you reuse the exact same partition string across windows to share the session. [2][3]
- If you want session (release health) capture tied to main process vs window focus, choose the appropriate integration:
- Default MainProcessSession captures sessions for the main process; use BrowserWindowSession in renderers if you prefer per-window sessions. You can remove or configure MainProcessSession via integrations. [4]
- Avoid creating a Session with options after it’s been used — Electron cannot change options for an already-created partition. Create partitions with the desired options before first use. [2]
- If using IPCMode.Classic on older Electron versions, test for namespace collisions (optional namespaced IPC is available in newer SDK versions) and ensure your preload scripts expose Sentry renderer setup appropriately. [1]
- For privacy/compliance, filter or redact PII in event/scope before sending; if some partitions should not report, exclude their sessions from getSessions. [1]
References
- Sentry Electron options (ipcMode, getSessions). [1]
- Electron session/fromPartition and BrowserWindow partition docs. [2][3]
- Sentry MainProcessSession integration (session capture behavior). [4]
References:
[1] Sentry for Electron — Options (ipcMode, getSessions). (docs.sentry.io)
[2] Electron — session/fromPartition docs. (electronjs.org)
[3] Electron — BrowserWindow partition option. (electronjs.org)
[4] Sentry for Electron — MainProcessSession integration. (docs.sentry.io)
If you want, I can draft the exact getSessions snippet and an example Sentry.init config for your app.
Citations:
- 1: https://docs.sentry.io/platforms/javascript/guides/electron/configuration/options/?utm_source=openai
- 2: https://www.electronjs.org/docs/latest/api/session?utm_source=openai
- 3: https://www.electronjs.org/docs/api/browser-window?utm_source=openai
- 4: https://docs.sentry.io/platforms/javascript/guides/electron/configuration/integrations/mainprocesssession/?utm_source=openai
🏁 Script executed:
find apps/desktop/src -name "*ipc*" -type fRepository: superset-sh/superset
Length of output: 121
🏁 Script executed:
rg "persist:superset" apps/desktop/src --type ts --type tsxRepository: superset-sh/superset
Length of output: 91
🏁 Script executed:
find apps/desktop/src -name "*constants*" -type f | head -10Repository: superset-sh/superset
Length of output: 571
🏁 Script executed:
rg "partition.*persist" apps/desktop/src --type ts --type tsx -A 2 -B 2Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
rg "persist:superset" apps/desktop/src --type tsRepository: superset-sh/superset
Length of output: 218
🏁 Script executed:
rg "partition.*persist" apps/desktop/src --type ts -A 2 -B 2Repository: superset-sh/superset
Length of output: 423
🏁 Script executed:
find apps/desktop/src -name "*ipc-channels*" -o -name "*ipc*channels*"Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
cat apps/desktop/src/shared/constants.tsRepository: superset-sh/superset
Length of output: 2047
🏁 Script executed:
rg "PARTITION\|SESSION_PARTITION\|SUPERSET_PARTITION" apps/desktop/src --type tsRepository: superset-sh/superset
Length of output: 46
🏁 Script executed:
rg "trpc" apps/desktop/src --type ts -l | head -5Repository: superset-sh/superset
Length of output: 299
🏁 Script executed:
cat apps/desktop/src/main/windows/main.ts | head -80Repository: superset-sh/superset
Length of output: 2552
🏁 Script executed:
rg "const.*=.*persist" apps/desktop/src --type tsRepository: superset-sh/superset
Length of output: 474
🏁 Script executed:
cat apps/desktop/src/shared/constants.ts | tail -30Repository: superset-sh/superset
Length of output: 1093
🏁 Script executed:
rg "partition.*persist.*superset" apps/desktop/src --type ts -B 5 -A 5Repository: superset-sh/superset
Length of output: 801
🏁 Script executed:
ast-grep --pattern 'webPreferences: { $$$partition: $_ $$$}'Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
grep -n "persist:superset" apps/desktop/src/main/lib/sentry.tsRepository: superset-sh/superset
Length of output: 113
🏁 Script executed:
grep -n "persist:superset" apps/desktop/src/main/windows/main.tsRepository: superset-sh/superset
Length of output: 100
🏁 Script executed:
head -50 apps/desktop/src/main/lib/sentry.tsRepository: superset-sh/superset
Length of output: 1224
Extract partition identifier to a shared constant.
The implementation correctly registers both default and custom sessions using getSessions with IPCMode.Classic, aligning with @sentry/electron v7.5.0 best practices. However, the hardcoded string "persist:superset" appears duplicated in both sentry.ts (line 31) and windows/main.ts (line 63).
Per coding guidelines, extract this to a named constant in apps/desktop/src/shared/constants.ts and import it in both files to maintain a single source of truth:
export const SUPERSET_PARTITION = "persist:superset";Then use session.fromPartition(SUPERSET_PARTITION) here and partition: SUPERSET_PARTITION in windows/main.ts.
🤖 Prompt for AI Agents
In `@apps/desktop/src/main/lib/sentry.ts` around lines 12 - 33, Hardcoded
partition string "persist:superset" is duplicated; extract it as an exported
constant named SUPERSET_PARTITION in the shared constants module, then replace
the literal in initSentry's getSessions (session.fromPartition(...)) with
session.fromPartition(SUPERSET_PARTITION) and replace the literal used for the
BrowserWindow partition setting in the windows main module with
SUPERSET_PARTITION; add the appropriate import of SUPERSET_PARTITION where
initSentry (getSessions) and the window creation code reference the partition.
Fix `net::ERR_UNKNOWN_URL_SCHEME` errors for `sentry-ipc://` URLs by switching from Protocol IPC mode to Classic IPC mode. Changes: - Add Sentry preload script import to enable Classic IPC mode - Bundle @sentry/electron in preload (exclude from externalization) - Use IPCMode.Classic to avoid protocol registration timing issues - Add getSessions to include custom session partition - Move initSentry() to after app.whenReady() since Classic mode allows this
Summary
net::ERR_UNKNOWN_URL_SCHEMEerrors forsentry-ipc://in productionpersist:superset) for isolation, but Sentry only registers its IPC protocol handler forsession.defaultSessionby defaultgetSessionsoption to include the custom partitioninitSentry()afterapp.whenReady()sincesession.fromPartition()requires the app to be readyTest plan
Summary by CodeRabbit
Chores
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.