# Behavior traces — electron/electron

> Canonical page: https://codevetter.com/unpack/electron/behavior-traces

# Behavior traces — electron/electron

Scanned commit 56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three flows define the system's shape. (1) Cold start: platform main → ElectronMainDelegate hooks → ElectronBrowserMainParts builds V8+Node, loads the app package, runs the bundled init which loads the app's main script, then Chromium's BrowserMain continues. (2) ipcRenderer.invoke: mojo message → ElectronApiIPCHandlerImpl → IpcMainEvent → JS ipcMain handler → reply through a ReplyChannel. (3) protocol.handle: a renderer request hits the session's protocol registry, calls the JS handler with a Request, and streams the Response back to the loader.
- Browser-process startup order: main() → content::ContentMain → ElectronMainDelegate::BasicStartupComplete (env vars ELECTRON_ENABLE_STACK_DUMPING/ELECTRON_DISABLE_SANDBOX, RegisterPathProvider, root-without-sandbox fatal check on Linux) → PreSandboxStartup (logging, crash keys, ResourceBundle for subprocesses, --allow-file-access-from-files) → PreBrowserMain (FieldTrialList, InitializeFeatureList, InitializeMojoCore). — [shell/app/electron_main_linux.cc#L49](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_linux.cc#L49) [shell/app/electron_main_delegate.cc#L216-L284](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L216-L284) [shell/app/electron_main_delegate.cc#L286-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L286-L410)
- Startup continued: ElectronBrowserMainParts::PostEarlyInitialization sets up WASM trap handlers (fuse-gated), creates JavascriptEnvironment, node_bindings_->Initialize → CreateEnvironment → sets unhandled_rejections='warn-with-error-code' → ElectronBindings::BindTo → LoadAppPackage → node_bindings_->LoadEnvironment (runs the browser bundle = lib/browser/init.ts) → JoinAppCode → re-initializes the FeatureList so app-set command-line switches take effect. — [shell/browser/electron_browser_main_parts.cc#L290-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L290-L410)
- lib/browser/init.ts order: require common init (module aliases, uv-loop wrapping) → set EventEmitter prototype on the native binding → install uncaughtException→dialog.showErrorBox handler → map process.exit→app.exit → require ipc-dispatch, rpc-server, guest-view-manager → read 'appPackage' hidden value → app.setAppPath → pre-populate protocol/service-worker-main/web-contents/web-frame-main modules → default window-all-closed→app.quit handler → apply v8Flags → load main entry → appCodeLoaded. — [lib/browser/init.ts#L10-L121](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L10-L121)
- new BrowserWindow(): JS constructor reaches the native object from process._linkedBinding('electron_browser_window'), whose _init freeze-wraps id, merges setBounds args with getBounds, re-emits focus/blur on app as 'browser-window-focus/blur', debounces 'unresponsive' (50ms; 5s during close), tracks _browserViews, emits 'browser-window-created' on app, then loadURL etc. forward to webContents. — [lib/browser/api/browser-window.ts#L4-L82](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/browser-window.ts#L4-L82) [lib/browser/api/browser-window.ts#L118-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/browser-window.ts#L118-L128)
- Renderer script-context flow: Blink creates a script context → ElectronRendererClient::DidCreateScriptContext → ShouldLoadPreload gate → first-time NodeBindings::Initialize/SetUpIsolate (then restores Blink's WASM streaming callback) → per-frame FrameEnvironment + node::InitializeContext → document load deferred (kStrict) → CreateEnvironment registers UndeferLoad callback → BindTo + BindProcess → preload paths stored as hidden 'preloadPaths'. — [shell/renderer/electron_renderer_client.cc#L133-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L133-L204) [shell/renderer/renderer_client_base.cc#L389-L416](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/renderer_client_base.cc#L389-L416)
- Preload execution order in lib/renderer/init.ts: patch Module._load to warn on 'vm' → override Module.wrapper to keep process/global/Buffer for preloads → common init → read webPreferences (nodeIntegration) → set up node globals only if nodeIntegration → load cjsPreloads synchronously (errors → BROWSER_PRELOAD_ERROR IPC) → esmPreloads via runEntryPointWithESMLoader → onPreloadsLoaded deletes node globals when !nodeIntegration && !contextIsolated → appCodeLoaded → UndeferLoad unfreezes the document. — [lib/renderer/init.ts#L11-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L11-L41) [lib/renderer/init.ts#L125-L180](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L125-L180)
- ipcRenderer.invoke('ch', ...args): the renderer binding sends ElectronApiIPC.Invoke over the associated mojo channel → ElectronApiIPCHandlerImpl::Invoke resolves api::Session from the frame's BrowserContext → MakeIPCEvent builds api::IpcMainEvent carrying the mojo InvokeCallback (ReplyChannel) → ipc_dispatch::Invoke looks up IpcMainImpl._invokeHandlers['ch'] → return value/promise serialized back through SerializedValue to the renderer promise. — [shell/browser/electron_api_ipc_handler_impl.cc#L66-L84](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L66-L84) [shell/browser/electron_api_ipc_handler_impl.cc#L158-L188](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L158-L188) [lib/browser/ipc-main-impl.ts#L15-L35](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-main-impl.ts#L15-L35) [lib/browser/ipc-dispatch.ts#L5-L7](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-dispatch.ts#L5-L7)
- If the Session or WebContents wrapper is gone when an Invoke arrives, MakeIPCEvent still invokes the reply callback with an error via ReplyChannel::SendError so the renderer promise rejects instead of hanging. — [shell/browser/electron_api_ipc_handler_impl.cc#L163-L184](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L163-L184)
- protocol.handle('app', handler) on a custom scheme: registerProtocol stores the callback → a request arrives as ProtocolRequest → convertToRequestBody rebuilds uploadData → a Request is constructed (initiatorOrigin attached as own prop, 'null' origin header stripped) → await handler(req) → validateResponse → if the Response is an untouched net.fetch result, relayUntouchedFetch holds the URL loader and streams prefix+remainder natively; otherwise res.body is wrapped with Readable.fromWeb → cb({data, headers, statusCode, statusText, mimeType}). — [lib/browser/api/protocol.ts#L152-L200](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L152-L200)
- utilityProcess.fork flow: JS validates options (execArgv array, serviceName string, stdio triple with stdin forced 'ignore') → native _fork launches a utility process → the returned handle emits 'stdout'/'stderr' events carrying fds that JS wraps in Socket→PassThrough pipes → 'exit' nulls the handle and tears down streams. — [lib/browser/api/utility-process.ts#L53-L117](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/utility-process.ts#L53-L117) [shell/services/node/node_service.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/services/node/node_service.cc)
- ELECTRON_RUN_AS_NODE flow: lib/node/init.ts patches child_process.fork to inject ELECTRON_RUN_AS_NODE=1 (and helperExecPath on macOS); on Linux, spawn/spawnSync are wrapped to forward CRASHDUMP_SIGNAL_FD/CRASHPAD_HANDLER_PID env pairs to such children; shell/app/node_main.cc detects the env var and runs plain Node instead of Chromium. — [lib/node/init.ts#L6-L75](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L6-L75) [shell/app/node_main.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/node_main.cc)
- V8 snapshot integrity: when the embedded_asar_integrity_validation fuse is on, a validator registered via gin::SetV8SnapshotValidator CHECK-fails startup unless the snapshot's SHA-256 equals the compiled-in snapshot_checksum::kChecksum. — [shell/app/electron_main_delegate.cc#L165-L177](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L165-L177) [shell/app/electron_main_delegate.cc#L202-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L202-L204)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
