# How Modly Handles Global Exception Handling and Logging in Electron

> Discover how Modly implements global exception handling and logging in Electron. Learn how it captures crashes, forwards them to the renderer, and records every runtime failure for robust diagnostics.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: how-to-guide
- Published: 2026-08-21

---

**Modly centralizes all diagnostic output through a dedicated logger service in [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts) and registers global `uncaughtException` and `unhandledRejection` listeners in [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts) to capture crashes, forward them to the renderer via IPC, and ensure no runtime failure goes unrecorded.**

Modly, an open-source Electron application, implements a robust error management strategy that ensures every runtime failure is captured, logged, and communicated to the user interface. By funneling all diagnostic output through a single **logger** service and wiring global exception handlers to the renderer process, the application maintains a reliable audit trail across both main and renderer contexts. This article examines the specific implementation details of Modly's global exception handling and logging architecture as found in the `lightningpixel/modly` repository.

## Centralized Logger Architecture

All logging in Modly flows through a single export from [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts). This module exposes a **logger** object with methods for every severity level, including a custom `python` method used specifically by the Python bridge.

The logger provides standardized methods such as `info`, `warn`, `error`, and `python`, ensuring consistent formatting and transport configuration across the entire codebase. Any module requiring diagnostics simply imports the singleton:

```typescript
import { logger } from './logger';

logger.info(`Operation completed successfully`);
logger.error(`Failed to process request`);

```

## Global Exception Handlers in the Main Process

To prevent silent crashes, Modly registers process-level listeners immediately upon startup in [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts). These handlers capture both synchronous throws and asynchronous rejections that escape normal try/catch blocks.

### Trapping Uncaught Exceptions

The `uncaughtException` handler filters out benign **EPIPE** errors—which occur when the launching terminal closes—and logs everything else before notifying the UI:

```typescript
// electron/main/index.ts
process.on('uncaughtException', (err) => {
  if ((err as NodeJS.ErrnoException).code === 'EPIPE') return;
  logger.error(`Uncaught exception: ${err.stack ?? err.message}`);
  mainWindow?.webContents.send('app:error', err.stack ?? err.message);
});

```

This design prevents pipe-related noise from polluting logs while ensuring critical stack traces reach both the filesystem and the user interface.

### Capturing Unhandled Promise Rejections

Asynchronous failures are handled via the `unhandledRejection` event. The handler converts the rejection reason to a string, logs it through the central logger, and forwards it to the renderer using the same IPC channel:

```typescript
// electron/main/index.ts
process.on('unhandledRejection', (reason) => {
  const msg = String(reason);
  logger.error(`Unhandled rejection: ${msg}`);
  mainWindow?.webContents.send('app:error', msg);
});

```

## Bidirectional Error Communication

Modly establishes a two-way error reporting pipeline between the main and renderer processes, ensuring developers receive complete context regardless of which process originates the failure.

### Forwarding Main Process Errors to the Renderer

When the global handlers catch an exception, they transmit the error message to the renderer via the `app:error` IPC channel. This allows the frontend to display user-friendly error notifications while the main process handles the technical logging:

```typescript
mainWindow?.webContents.send('app:error', err.stack ?? err.message);

```

### Ingesting Renderer-Side Errors

The main process also listens for explicit error reports from the renderer. In [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts), Modly registers a listener on the `log:error` channel that prefixes the message with its origin and routes it through the central logger:

```typescript
// electron/main/ipc-handlers.ts
ipcMain.on('log:error', (_event, message: string) => 
  logger.error(`[Renderer] ${message}`)
);

```

Renderer code can trigger this pipeline when catching local exceptions:

```typescript
// In renderer process
window.electron.ipcRenderer.send('log:error', errorMessage);

```

## Specialized Logging for the Python Bridge

Modules interacting with external processes utilize the logger's custom methods. In [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts), stdout and stderr from the Python subprocess are routed through `logger.python()`, keeping native process output in the same log stream as Electron's internal diagnostics:

```typescript
// electron/main/python-bridge.ts
logger.python(msg);               // regular output
logger.python(`[stderr] ${msg}`); // error output

```

## Application Lifecycle Logging

When the application finishes initializing, Modly records a startup marker that includes the current version, providing a clear boundary in log files for debugging session-related issues:

```typescript
// electron/main/index.ts
logger.info(`App started — version ${app.getVersion()}`);

```

## Summary

- **Centralized Service**: All logging flows through [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts), providing consistent formatting and transport logic.
- **Global Handlers**: The main process registers `uncaughtException` and `unhandledRejection` listeners in [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts) to capture fatal errors.
- **Noise Filtering**: The exception handler explicitly ignores **EPIPE** errors to prevent terminal-disconnect crashes.
- **UI Integration**: Errors are forwarded to the renderer via the `app:error` IPC channel, enabling real-time user feedback.
- **Bidirectional Flow**: Renderer errors flow back to the main logger through the `log:error` IPC channel handled in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts).
- **Python Integration**: The `logger.python()` method in [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts) consolidates subprocess output with application logs.

## Frequently Asked Questions

### How does Modly prevent EPIPE errors from crashing the application?

In [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts), the `uncaughtException` handler checks the error code and immediately returns if it equals `'EPIPE'`. This prevents the application from terminating when the parent terminal closes, while still logging genuine runtime exceptions.

### What IPC channels does Modly use for error reporting?

Modly uses two primary channels: `app:error` for main-to-renderer communication (sending crashes to the UI), and `log:error` for renderer-to-main communication (forwarding frontend errors to the central log file).

### Can Modly's logger handle output from Python subprocesses?

Yes. The [`electron/main/python-bridge.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/python-bridge.ts) module uses a custom `logger.python()` method exposed by [`electron/main/logger.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/logger.ts) to route both stdout and stderr from the Python interpreter into the same consolidated log pipeline used by the Electron main process.

### Where are global exception handlers registered in Modly's codebase?

The global `process.on('uncaughtException')` and `process.on('unhandledRejection')` listeners are registered in [`electron/main/index.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/index.ts), ensuring they are active immediately upon application startup and remain active for the entire lifecycle of the main process.