# How Cherry Studio's Crash Reporting System Detects and Handles Renderer Unresponsiveness

> Learn how Cherry Studio's crash reporting system detects renderer unresponsiveness using Electron's built-in crashReporter and custom listeners for graceful recovery.

- Repository: [CherryHQ/cherry-studio](https://github.com/cherryhq/cherry-studio)
- Tags: internals
- Published: 2026-02-27

---

**Cherry Studio uses Electron's built-in crashReporter combined with custom main-process listeners to capture JavaScript call stacks during renderer hangs and implement graceful recovery strategies after hard crashes.**

Cherry Studio is an Electron-based desktop application that implements a comprehensive crash reporting system to monitor renderer process health. The system leverages Electron's native crashReporter API alongside custom event listeners to detect unresponsive states, capture diagnostic call stacks, and manage recovery from fatal crashes.

## Initializing the Crash Reporter in the Main Process

The crash reporting system activates immediately when the application launches. In [`src/main/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/index.ts), the main process initializes Electron's crashReporter with a local-only configuration that prevents automatic upload to remote servers while ensuring crash dumps are preserved locally.

```typescript
import { crashReporter } from 'electron';

crashReporter.start({
  companyName: 'CherryHQ',
  productName: 'CherryStudio',
  submitURL: '',
  uploadToServer: false,
});

```

This configuration, found at lines 46-52 of [`src/main/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/index.ts), ensures that **native crash dumps** are written to the user's local filesystem without transmitting sensitive data to external servers.

## Detecting Renderer Unresponsiveness

Beyond fatal crashes, the crash reporting system monitors for **renderer unresponsiveness**—a state where the UI thread becomes blocked without triggering a native crash. Cherry Studio attaches listeners to every `webContents` instance created by the application.

### Capturing JavaScript Call Stacks

When the renderer enters an unresponsive state, the system immediately invokes `collectJavaScriptCallStack()` to capture the current execution context. This Electron API extracts the JavaScript call stack from the main frame of the renderer process, providing diagnostic data that standard crash dumps cannot capture for hang conditions.

```typescript
app.on('web-contents-created', (_, webContents) => {
  webContents.on('unresponsive', async () => {
    logger.error('Renderer unresponsive start');
    const callStack = await webContents.mainFrame.collectJavaScriptCallStack();
    logger.error(`Renderer unresponsive js call stack\n ${callStack}`);
  });
});

```

This implementation, located at lines 107-112 of [`src/main/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/index.ts), writes the captured stack trace to the application's error logs alongside the unresponsive event timestamp, enabling developers to identify infinite loops or blocking operations causing the hang.

## Handling Hard Renderer Crashes

For fatal renderer process terminations, Cherry Studio implements a recovery mechanism in [`src/main/services/WindowService.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/services/WindowService.ts). The service listens for the `render-process-gone` event, which fires when the renderer crashes or is killed by the operating system.

```typescript
mainWindow.webContents.on('render-process-gone', (_, details) => {
  logger.error(`Renderer process crashed with: ${JSON.stringify(details)}`);
  const now = Date.now();
  const lastCrash = this.lastRendererProcessCrashTime;
  this.lastRendererProcessCrashTime = now;
  
  if (now - lastCrash > 60_000) {
    mainWindow.webContents.reload();
  } else {
    app.exit(1);
  }
});

```

This code, found at lines 138-148 of [`src/main/services/WindowService.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/services/WindowService.ts), logs crash details and implements intelligent recovery logic.

### Crash Loop Prevention

The crash reporting system includes **intelligent crash loop detection**. By tracking the timestamp of the previous crash using `lastRendererProcessCrashTime`, the system distinguishes between isolated incidents and persistent startup failures. If two crashes occur within 60 seconds, the application terminates completely rather than attempting another reload, preventing resource exhaustion and log spam.

## Summary

Cherry Studio's crash reporting system provides comprehensive visibility into renderer process health through three integrated mechanisms:

- **Local crash dump collection** via Electron's crashReporter, configured to preserve privacy by disabling server uploads
- **JavaScript call stack capture** during unresponsive events using `collectJavaScriptCallStack()`, enabling diagnosis of UI hangs without native crashes
- **Intelligent crash recovery** with loop detection that reloads the renderer after isolated crashes but exits the application during persistent failure cycles

## Frequently Asked Questions

### How does Cherry Studio detect when the renderer becomes unresponsive?

The application listens for the `unresponsive` event on every `webContents` instance created by the main process. When this event fires—indicating the renderer's main thread has been blocked for a period of time—the system immediately attempts to collect diagnostic data before the process potentially crashes.

### What information is captured when a renderer hang occurs?

When unresponsiveness is detected, Cherry Studio invokes `webContents.mainFrame.collectJavaScriptCallStack()` to extract the current JavaScript execution stack from the renderer's main frame. This call stack is written to the error log alongside a timestamp, providing developers with the exact code path that caused the UI thread to block.

### How does the application prevent crash loops?

The `WindowService` tracks the timestamp of each renderer crash using `lastRendererProcessCrashTime`. If a second crash occurs within 60 seconds of the previous one, the application calls `app.exit(1)` to terminate completely rather than reloading the renderer. This prevents the application from entering an infinite crash-reload cycle that would consume system resources and generate excessive log files.

### Where are crash dumps stored in Cherry Studio?

Crash dumps are stored locally on the user's machine because the crash reporter is initialized with `uploadToServer: false` and an empty `submitURL`. Electron writes these dumps to the platform-specific crash dump directory (typically within the application's user data folder), ensuring that sensitive debugging information remains under the user's control while still being available for manual analysis.