docs: overhaul crash reporting documentation (#54280)

* docs: overhaul crash reporting documentation

Add a Crash Reporting tutorial covering how Crashpad collects minidumps,
setting up crashReporter, attaching context with globalExtra and
per-process parameters, reacting to process-gone events, receiving
uploads, symbolicating with Electron's published symbols, and hosted
services.

Correct the crashReporter API reference: value limit is 20320 bytes (not
127) and long keys emit a warning; rateLimit works on all platforms;
ignoreSystemCrashHandler has no effect on Windows; compress: false is
deprecated; getParameters() excludes globalExtra; getUploadedReports()
also lists reports that were not uploaded; Node child processes have no
process.crashReporter.start(); document ptype and _companyName in the
payload; note MAS no-op behaviour; drop the archived mini-breakpad-server
and Mozilla-only Socorro and move hosted services to the tutorial.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: trim implementation details from crash reporting docs

Document behaviour rather than internals so the docs don't become an
accidental API contract: drop the crash dumps directory layout and file
naming, handler process details, Chromium-internal upload fields and
query parameters, exact release asset names and the symbol server path
format, and notes about behaviour from old Electron versions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: remove privacy section from crash reporting tutorial

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: recommend electron-minidump for symbolication

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: move default values to end of crashReporter option descriptions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: address crash reporting review feedback

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

* docs: link crashReporter methods in MAS note

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFzbSEnmLgZoxGXgEKSH4i

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
claude[bot]andClaude Opus 5.5 authored and GitHub committed 2026-09-24 14:20:41 -07:00
1 parent 1c36d90659
commit 718c8a6425
4 files changed
+458 -57

No files matched your search

+1
View File
@@ -58,6 +58,7 @@ an issue:
* [DevTools Extension](tutorial/devtools-extension.md)
* [Automated Testing](tutorial/automated-testing.md)
* [REPL](tutorial/repl.md)
* [Crash Reporting](tutorial/crash-reporting.md)
* [Distribution](tutorial/application-distribution.md)
* [Code Signing](tutorial/code-signing.md)
* [Mac App Store](tutorial/mac-app-store-submission-guide.md)
+2 -1
View File
@@ -656,7 +656,8 @@ Returns `string` - The current application directory.
* `videos` Directory for a user's videos.
* `recent` Directory for the user's recent files (Windows only).
* `logs` Directory for your app's log folder.
* `crashDumps` Directory where crash dumps are stored.
* `crashDumps` Directory where crash dumps are stored. See
[Crash Reporting](../tutorial/crash-reporting.md#what-happens-when-your-app-crashes).
Returns `string` - A path to a special directory or file associated with `name`. On
failure, an `Error` is thrown.
+82 -56
View File
@@ -19,30 +19,27 @@ const { crashReporter } = require('electron')
crashReporter.start({ submitURL: 'https://your-domain.com/url-to-submit' })
```
For setting up a server to accept and process crash reports, you can use
following projects:
For a guide to collecting, receiving and symbolicating crash reports, including
how to run your own crash server or use a hosted service, see the
[Crash Reporting](../tutorial/crash-reporting.md) tutorial.
* [socorro](https://github.com/mozilla-services/socorro)
* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server)
Electron uses [Crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md)
to monitor and report crashes. Crashpad uses the same
[upload protocol](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/overview_design.md#Upload-to-collection-server)
as Breakpad, so servers that accept Breakpad minidumps can receive Electron's
crash reports.
> [!NOTE]
> Electron uses Crashpad, not Breakpad, to collect and upload
> crashes, but for the time being, the [upload protocol is the same](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/overview_design.md#Upload-to-collection-server).
Crash reports are stored under the directory returned by
[`app.getPath('crashDumps')`](app.md#appgetpathname). You can override it by calling
[`app.setPath('crashDumps', '/path/to/crashes')`](app.md#appsetpathname-path) before starting the crash
reporter. The layout of files inside this directory is an implementation detail
and may change between versions of Electron.
Or use a 3rd party hosted solution:
* [Backtrace](https://backtrace.io/electron/)
* [Sentry](https://docs.sentry.io/clients/electron)
* [BugSplat](https://www.bugsplat.com/docs/platforms/electron)
* [Bugsnag](https://docs.bugsnag.com/platforms/electron/)
Crash reports are stored temporarily before being uploaded in a directory
underneath the app's user data directory, called 'Crashpad'. You can override
this directory by calling `app.setPath('crashDumps', '/path/to/crashes')`
before starting the crash reporter.
Electron uses [crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md)
to monitor and report crashes.
The `crashReporter` module is disabled in Mac App Store builds. Its methods can
be called, but they do nothing: no crash reports are collected or uploaded,
[`getUploadedReports()`](#crashreportergetuploadedreports) returns an empty array and
[`getUploadToServer()`](#crashreportergetuploadtoserver) returns
`false`.
On Windows, some crashes never reach an in-process crash handler, most notably
`__fastfail` terminations (`STATUS_STACK_BUFFER_OVERRUN`, raised by
@@ -90,13 +87,16 @@ changes:
* `uploadToServer` boolean (optional) - Whether crash reports should be sent
to the server. If false, crash reports will be collected and stored in the
crashes directory, but not uploaded. Default is `true`.
* `ignoreSystemCrashHandler` boolean (optional) - If true, crashes generated
in the main process will not be forwarded to the system crash handler.
Default is `false`.
* `rateLimit` boolean (optional) _macOS_ _Windows_ - If true, limit the
number of crashes uploaded to 1/hour. Default is `false`.
* `ignoreSystemCrashHandler` boolean (optional) _macOS_ _Linux_ - If true,
crashes generated in the main process will not be forwarded to the system
crash handler. This option has no effect on Windows. Default is `false`.
* `rateLimit` boolean (optional) - If true, limit the number of crashes
uploaded to 1/hour. Crash reports over the limit are not uploaded, but are
still stored on disk. Default is `false`.
* `compress` boolean (optional) - If true, crash reports will be compressed
and uploaded with `Content-Encoding: gzip`. Default is `true`.
and uploaded with `Content-Encoding: gzip`. Setting this
to `false` while `uploadToServer` is `true` is deprecated and logs a
deprecation warning. Default is `true`.
* `extra` Record\<string, string\> (optional) - Extra string key/value
annotations that will be sent along with crash reports that are generated
in the main process. Only string values are supported. Crashes generated in
@@ -110,7 +110,8 @@ changes:
been started. If a key is present in both the global extra parameters and
the process-specific extra parameters, then the global one will take
precedence. By default, `productName` and the app version are included, as
well as the Electron version.
well as the Electron version. Global extra parameters are not returned by
[`getParameters()`](#crashreportergetparameters).
This method must be called before using any other `crashReporter` APIs. Once
initialized this way, the crashpad handler collects crashes from all
@@ -132,10 +133,10 @@ by the crash reporter.
> [!NOTE]
> Parameters passed in `extra`, `globalExtra` or set with
> `addExtraParameter` have limits on the length of the keys and values. Key names
> must be at most 39 bytes long, and values must be no longer than 127 bytes.
> Keys with names longer than the maximum will be silently ignored. Key values
> longer than the maximum length will be truncated.
> `addExtraParameter` have limits on the length of the keys and values. Key
> names must be at most 39 bytes long, and values must be no longer than 20320
> bytes. Keys with names longer than the maximum are ignored, and a warning is
> emitted. Values longer than the maximum length are truncated.
> [!NOTE]
> This method is only available in the main process.
@@ -152,9 +153,13 @@ changes:
-->
Returns [`CrashReport | null`](structures/crash-report.md) - The date and ID of the
last crash report. Only crash reports that have been uploaded will be returned;
even if a crash report is present on disk it will not be returned until it is
uploaded. In the case that there are no uploaded reports, `null` is returned.
crash report with the most recent upload time, from the list returned by
[`getUploadedReports()`](#crashreportergetuploadedreports). If there are no crash
reports at all, `null` is returned.
If no report has been uploaded yet but some are stored on disk, a report that has
not been uploaded may be returned. Check that its `id` is not empty before
treating it as uploaded.
> [!NOTE]
> This method is only available in the main process.
@@ -172,8 +177,14 @@ changes:
Returns [`CrashReport[]`](structures/crash-report.md):
Returns all uploaded crash reports. Each report contains the date and uploaded
ID.
Returns the crash reports stored on disk. Each report contains the date it was
uploaded and the ID that the crash server returned for it.
Despite the method's name, reports that have not been uploaded (for example
because `uploadToServer` is `false`, the upload failed, or the report was rate
limited) are included too. For those reports, `id` is an empty string and `date`
is not meaningful. To list only uploaded reports, filter out reports with an
empty `id`.
> [!NOTE]
> This method is only available in the main process.
@@ -217,11 +228,13 @@ called before `start` is called.
### `crashReporter.addExtraParameter(key, value)`
* `key` string - Parameter key, must be no longer than 39 bytes.
* `value` string - Parameter value, must be no longer than 127 bytes.
* `value` string - Parameter value, must be no longer than 20320 bytes.
Set an extra parameter to be sent with the crash report. The values specified
here will be sent in addition to any values set via the `extra` option when
`start` was called.
`start` was called. Calling this again with the same key replaces the value.
The value is read when a crash happens, so you can update it as your app's
state changes.
Parameters added in this fashion (or via the `extra` parameter to
`crashReporter.start`) are specific to the calling process. Adding extra
@@ -229,12 +242,15 @@ parameters in the main process will not cause those parameters to be sent along
with crashes from renderer or other child processes. Similarly, adding extra
parameters in a renderer process will not result in those parameters being sent
with crashes that occur in other renderer processes or in the main process.
Processes created with [`utilityProcess`](utility-process.md) have no API for
setting extra parameters, so only `globalExtra` values are sent with their
crashes.
> [!NOTE]
> Parameters have limits on the length of the keys and values. Key
> names must be no longer than 39 bytes, and values must be no longer than 20320
> bytes. Keys with names longer than the maximum will be silently ignored. Key
> values longer than the maximum length will be truncated.
> bytes. Keys with names longer than the maximum are ignored, and a warning is
> emitted. Values longer than the maximum length are truncated.
### `crashReporter.removeExtraParameter(key)`
@@ -245,21 +261,21 @@ will not include this parameter.
### `crashReporter.getParameters()`
Returns `Record<string, string>` - The current 'extra' parameters of the crash reporter.
Returns `Record<string, string>` - The current 'extra' parameters of the crash
reporter in the calling process, as set with the `extra` option and
`addExtraParameter`. Parameters set with the `globalExtra` option are not
included.
## In Node child processes
Since `require('electron')` is not available in Node child processes, the
following APIs are available on the `process` object in Node child processes.
Since `require('electron')` is not available in Node child processes (processes
run with `ELECTRON_RUN_AS_NODE`, such as those created with
`child_process.fork()`), the following APIs are available on the `process`
object in Node child processes.
#### `process.crashReporter.start(options)`
See [`crashReporter.start()`](#crashreporterstartoptions).
Note that if the crash reporter is started in the main process, it will
automatically monitor child processes, so it should not be started in the child
process. Only use this method if the main process does not initialize the crash
reporter.
If the crash reporter is started in the main process, Node child processes are
monitored automatically. There is no way to start the crash reporter from a
Node child process.
#### `process.crashReporter.getParameters()`
@@ -276,18 +292,28 @@ See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparamet
## Crash Report Payload
The crash reporter will send the following data to the `submitURL` as
a `multipart/form-data` `POST`:
a `multipart/form-data` `POST`. Unless `compress` is `false`, the request body
is gzip-compressed and sent with `Content-Encoding: gzip`.
* `ver` string - The version of Electron.
* `platform` string - e.g. 'win32'.
* `process_type` string - e.g. 'renderer'.
* `process_type` string - e.g. 'renderer', or 'browser' for the main process.
* `guid` string - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'.
* `_version` string - The version in `package.json`.
* `_productName` string - The product name in the `crashReporter` `options`
object.
* `prod` string - Name of the underlying product. In this case Electron.
* `_companyName` string - The company name in the `crashReporter` `options`
object.
object. Only sent if the deprecated `companyName` option is set.
* `upload_file_minidump` File - The crash report in the format of `minidump`.
* All level one properties of the `extra` object in the `crashReporter`
* All level one properties of the `globalExtra` object in the `crashReporter`
`options` object.
* All extra parameters of the process that crashed, set with the `extra`
option (main process only) or `addExtraParameter`.
Crashpad and Chromium may add other fields to the upload. These are not part
of Electron's API and can change without notice, so don't rely on them.
The body of the server's response is stored as the crash report's ID, and is
returned in the `id` field by
[`getUploadedReports()`](#crashreportergetuploadedreports).
+373
View File
@@ -0,0 +1,373 @@
# Crash Reporting
## Overview
When a native crash happens in your app (e.g. a segfault in Chromium, a fatal V8 error, an
out-of-memory renderer, or a bug in a native Node.js module), there is no JavaScript
exception to catch. Electron's [`crashReporter`](../api/crash-reporter.md) module
captures these crashes as minidumps that you can collect, upload and turn back into
readable stack traces.
This guide covers how crash reporting works in Electron, how to attach useful context to
reports, how to receive them, and how to symbolicate them.
## What happens when your app crashes
Electron uses [Crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md),
the same crash reporting system as Chromium. When you call `crashReporter.start()` in the
main process:
1. Electron starts a separate crash handler process.
2. Child processes created after `start()` is called (renderers, the GPU process, utility
processes and Node.js child processes) are monitored automatically.
3. When a monitored process crashes, the handler writes a minidump: a snapshot of the
crashed process's threads, stacks and loaded modules. This works even when the crashed
process is too broken to run any code of its own.
4. If uploads are enabled, the handler sends the minidump to your `submitURL`, along with
the annotations (key/value metadata) that were set when the process crashed.
Crash reports are stored under the directory returned by `app.getPath('crashDumps')`. To
store them somewhere else, call `app.setPath('crashDumps', path)` before calling
`crashReporter.start()`. The layout of files inside this directory is an implementation
detail and may change between versions of Electron, so don't depend on it.
## Setting up the crash reporter
Call `crashReporter.start()` in the main process as early as possible, ideally before
`app.whenReady()`. Renderer and child processes that start before the crash reporter
won't be monitored.
```js title='main.js'
const { app, crashReporter } = require('electron')
crashReporter.start({
submitURL: 'https://crashes.example.com/submit',
uploadToServer: true,
globalExtra: {
releaseChannel: 'beta'
}
})
app.whenReady().then(() => {
// create windows...
})
```
The options that matter most are:
* `submitURL` - Where crash reports are sent, as a `multipart/form-data` `POST`.
Required unless `uploadToServer` is `false`.
* `uploadToServer` - Whether to upload reports. If you ask users for consent to send
crash reports, start with `uploadToServer: false` and call
`crashReporter.setUploadToServer(true)` when they opt in. Reports are still written
to disk when uploads are disabled.
* `productName` - Sent as `_productName`. Defaults to `app.name`.
* `globalExtra` - Annotations that are sent with crashes from every process. See
[Attaching context to crash reports](#attaching-context-to-crash-reports).
* `extra` - Annotations for crashes in the main process only.
* `rateLimit` - Limits uploads to one per hour. Reports over the limit are not uploaded
but stay on disk.
* `compress` - Uploads are gzip-compressed (`Content-Encoding: gzip`) by default. Most
crash servers expect this. Setting `compress: false` is deprecated and logs a
warning.
* `ignoreSystemCrashHandler` - Stops main process crashes from also being passed to the
operating system's crash handler. This has no effect on Windows.
Calling `start()` a second time does nothing, and the crash reporter can't be stopped
once it has started.
To test your setup, call `process.crash()` from the process you want to crash.
### Mac App Store builds
The crash reporter is disabled in [Mac App Store](./mac-app-store-submission-guide.md)
builds of Electron. All `crashReporter` methods can still be called, but they do
nothing: no minidumps are written and `getUploadedReports()` always returns an empty
array. Crashes in MAS builds are reported only through Apple's own crash reporting.
### Sandboxed renderers and preload scripts
`crashReporter` is one of the modules available to [sandboxed](./sandbox.md) preload
scripts. In renderer processes it only provides `addExtraParameter()`,
`removeExtraParameter()` and `getParameters()`. The crash reporter itself is started in
the main process.
With [context isolation](./context-isolation.md) enabled, web content can't reach
`crashReporter` directly. Call it from your preload script, or expose a narrow function
with the [`contextBridge`](../api/context-bridge.md), as shown in the next section.
## Attaching context to crash reports
A stack trace tells you where a crash happened. Annotations tell you what the app was
doing at the time: which window was open, which feature was in use, which account type
the user has. Annotation values are captured at the moment of the crash, so what you get
is whatever the value was when the process died.
### Where annotations apply
There are two kinds of annotation, and it's important to put each value in the right
place:
* **`globalExtra`** is set once, in `crashReporter.start()`, and is sent with crashes
from every process. It can't be changed later. Use it for values that don't change
while the app is running, such as a release channel or build ID.
* **`extra` and `addExtraParameter()`** are per-process. A value set in the main
process is only sent with main process crashes. A value set in one renderer is only
sent when that renderer crashes. Each process has to set its own values.
If the same key is set in both `globalExtra` and a process's own parameters, the
`globalExtra` value is used.
Where you can set per-process values:
| Process | How to set values |
| --- | --- |
| Main | `extra` in `crashReporter.start()`, or `crashReporter.addExtraParameter()` |
| Renderer | `crashReporter.addExtraParameter()` in the preload script |
| Node.js child process (`child_process.fork()`) | `process.crashReporter.addExtraParameter()` |
| Utility process (`utilityProcess.fork()`) | No API. Only `globalExtra` values are sent. |
`crashReporter.getParameters()` returns the current process's own parameters. It does not
include `globalExtra`.
### Limits
* Key names must be at most 39 bytes long. Longer keys are ignored, and Electron emits a
process warning when you try to set one.
* Values are strings of at most 20320 bytes. Longer values are truncated.
* Limits are in bytes, not characters, so non-ASCII text uses up the limit faster.
### Keep annotations current
Because values are read at crash time, update them as your app's state changes. For
example, you can record how many windows are open and which feature the user is using
in the main process:
```js title='main.js'
const { app, crashReporter } = require('electron')
let windowCount = 0
app.on('browser-window-created', (event, win) => {
windowCount++
crashReporter.addExtraParameter('windowCount', String(windowCount))
win.on('closed', () => {
windowCount--
crashReporter.addExtraParameter('windowCount', String(windowCount))
})
})
async function exportProject() {
crashReporter.addExtraParameter('feature', 'export')
try {
// ...run the export
} finally {
crashReporter.removeExtraParameter('feature')
}
}
```
For renderer crashes, set values in the renderer. This preload script records the current
route of a single-page app and lets the page mark which feature is active. It only
accepts known keys, so the page can't fill reports with arbitrary data:
```js title='preload.js'
const { contextBridge, crashReporter } = require('electron')
const allowedKeys = new Set(['feature', 'route'])
contextBridge.exposeInMainWorld('crashContext', {
set: (key, value) => {
if (allowedKeys.has(key)) {
crashReporter.addExtraParameter(key, String(value))
}
}
})
window.addEventListener('DOMContentLoaded', () => {
crashReporter.addExtraParameter('route', location.pathname)
})
```
```js title='renderer.js' @ts-nocheck
window.crashContext.set('route', '/settings')
window.crashContext.set('feature', 'image-editor')
```
## Reacting to crashes at runtime
Minidumps are for diagnosing a crash later. To react when a process dies, for example to
log it or recover, listen for these events in the main process:
* [`render-process-gone`](../api/app.md#event-render-process-gone) on `app`, or on a
single [`webContents`](../api/web-contents.md#event-render-process-gone), for renderer
processes.
* [`child-process-gone`](../api/app.md#event-child-process-gone) on `app` for all other
child processes, such as the GPU and utility processes.
Both events provide a `reason` (such as `crashed`, `oom`, `killed` or `clean-exit`) and
an `exitCode`.
```js title='main.js'
const { app, BrowserWindow } = require('electron')
app.on('child-process-gone', (event, details) => {
console.error(`${details.type} process gone: ${details.reason} (exit code ${details.exitCode})`)
})
app.whenReady().then(() => {
const win = new BrowserWindow()
let recentCrashes = 0
win.webContents.on('render-process-gone', (event, details) => {
console.error(`Renderer gone: ${details.reason} (exit code ${details.exitCode})`)
if (details.reason === 'clean-exit') return
// Reload the page in a new renderer process, but don't retry forever.
recentCrashes++
if (recentCrashes <= 3) {
win.reload()
setTimeout(() => {
recentCrashes--
}, 60 * 1000)
}
})
win.loadFile('index.html')
})
```
## Receiving crash reports
### On your own server
Crash reports are sent to `submitURL` as a `multipart/form-data` `POST`, gzip-compressed
unless you set `compress: false`. The form contains:
* `upload_file_minidump` - The minidump file.
* `process_type` - The type of process that crashed, such as `renderer`, or `browser`
for the main process.
* `prod` - Always `Electron`.
* `ver` - The Electron version.
* `_productName` - The `productName` option, which defaults to `app.name`.
* `_version` - Your app's version, from `app.getVersion()`.
* `guid` - An ID for this installation.
* `platform` - `win32`, `darwin` or `linux`.
* Your `globalExtra` values and the crashed process's own parameters.
Crashpad and Chromium may add other fields. These aren't part of Electron's API and can
change without notice, so don't rely on them. See
[Crash Report Payload](../api/crash-reporter.md#crash-report-payload) for the full list
of documented fields.
Respond with a `200` status. The body of the response is stored as the report's ID, which
`crashReporter.getUploadedReports()` returns, so you can use it to link a user's report
to your server's record.
Crashpad uses the Breakpad upload protocol, so any server that accepts Breakpad or
Crashpad minidumps can receive Electron's reports.
### Collecting reports locally
If you set `uploadToServer: false`, crash reports are still written under
`app.getPath('crashDumps')`, but they are not sent anywhere. This is useful while
developing, or if you want to ask the user before sending anything: once they agree, call
`crashReporter.setUploadToServer(true)`. Only crashes that happen after that are
uploaded; reports written while uploads were disabled are not sent later.
Electron doesn't provide an API for reading minidump files from disk, and the layout of
the crash dumps directory can change between versions. If you need the minidumps
themselves, receive them with your own `submitURL` (which can be a server running on
the same machine) instead of reading files from the directory.
## Symbolicating crash reports
A minidump contains raw memory addresses, not function names. Electron's release builds
are stripped of debug information, so to turn those addresses into a readable stack
trace you need the symbol files for the exact Electron version, platform and
architecture that crashed. This is called symbolication.
### Getting Electron's symbols
Each [Electron release](https://github.com/electron/electron/releases) on GitHub ships
symbol archives for every platform it supports:
* [Breakpad](https://chromium.googlesource.com/breakpad/breakpad/) symbols for all
platforms. These are what most minidump tools use.
* dSYMs for macOS, for use with Apple's tools such as `atos` and `lldb`.
* PDBs for Windows, for use with WinDbg and Visual Studio.
* Debug info for Linux, for use with `gdb`.
Electron also runs a symbol server at `https://symbols.electronjs.org`. Tools that
support symbol servers can download the symbols they need from it, so you don't have to
download the archives for each version. For debuggers on Windows, see
[Setting Up Symbol Server in Debugger](../development/debugging-with-symbol-server.md).
### Example: symbolicating a minidump
The [`electron-minidump`](https://www.npmjs.com/package/electron-minidump) package
symbolicates an Electron minidump in one step. It works out which Electron version the
dump came from, downloads the matching symbols, and prints
the stack of every thread:
```sh
npx electron-minidump /path/to/crash.dmp
```
It runs on macOS and Linux, and can symbolicate dumps from any platform.
If you also have symbols for your own native code, pass a directory containing all the
Breakpad symbols to Breakpad's `minidump_stackwalk` tool instead.
### Symbols for your own code
Electron's symbols only cover Electron's own binaries. If your app includes native Node.js
modules or other native libraries, frames in those will stay unsymbolicated unless you
also keep symbols for them. Generate Breakpad symbols for each binary you ship with
Breakpad's `dump_syms` tool, and store them where your symbolication tool can find them. Keep them for every
version you release, since symbols only match the exact build they came from.
## macOS system crash reports
When an app crashes on macOS, the system may also write a crash report (an `.ips` file,
shown in the Console app) to `~/Library/Logs/DiagnosticReports`. For Electron's release
builds these reports are misleading: because the binaries are stripped, macOS labels each
frame with the nearest exported symbol plus a large offset, such as
`v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) + 2919558`. These
function names are almost always wrong.
To get a correct stack from one of these reports, use
[`@electron/symbolicate-mac`](https://github.com/electron/symbolicate-mac). It reads text
crash reports, spindumps and `sample` output, works out the Electron version from the
report's "Binary Images" section, and downloads the right symbols:
```sh
npx @electron/symbolicate-mac /path/to/crash.txt
```
For an `.ips` file, open it in the Console app and save the full text report, including
the "Binary Images" section, first.
You can also symbolicate individual addresses yourself with `atos` and the dSYM from the
matching release. Take the load address of `Electron Framework` from the "Binary Images"
section and the frame's address from the stack:
```sh
atos -arch arm64 -o "Electron Framework.dSYM/Contents/Resources/DWARF/Electron Framework" \
-l 0x109b49000 0x10ae32a06
```
## Using a hosted crash reporting service
Instead of running your own server, you can send crash reports to a hosted service. These
services receive Electron's minidumps, symbolicate them (usually with Electron's public
symbols) and group similar crashes. Many also offer SDKs that report JavaScript errors
alongside native crashes. Services with Electron support include:
* [Sentry](https://docs.sentry.io/platforms/javascript/guides/electron/)
* [BugSplat](https://docs.bugsplat.com/integrations/desktop/electron)
* [Backtrace](https://github.com/backtrace-labs/backtrace-javascript/tree/main/packages/electron) (part of Sauce Labs)
* [Bugsnag](https://docs.bugsnag.com/platforms/electron/)
This list is provided for convenience. The Electron project doesn't endorse or support
any of these services; check each one's documentation for how it works with Electron.