# How the Create React App Error Overlay Displays Runtime Errors

> Discover how Create React App's error overlay captures and displays runtime errors with a dedicated iframe UI. Learn about its internal mechanisms for error handling and presentation.

- Repository: [Meta/create-react-app](https://github.com/facebook/create-react-app)
- Tags: internals
- Published: 2026-02-26

---

**Create React App injects a development-only iframe-based UI called `react-error-overlay` that captures runtime exceptions via global error handlers, stores them as `ErrorRecord` objects, and renders a full-screen React component tree inside an isolated iframe.**

When you run `npm start` in a Create React App (CRA) project, the development environment includes a sophisticated error handling system designed to catch and display runtime JavaScript errors before they crash your application. According to the `facebook/create-react-app` source code, this system operates through a four-stage pipeline that bridges the webpack hot module replacement client and a dedicated React-based overlay UI.

## How the Error Overlay Captures Runtime Errors

The error detection mechanism begins long before any UI appears. It starts in the webpack development client and propagates through global browser error hooks.

### Registering the Runtime Error Listener in webpackHotDevClient

The entry point for error reporting is [`packages/react-dev-utils/webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/webpackHotDevClient.js). During initialization, this file calls `ErrorOverlay.startReportingRuntimeErrors()` with a callback that sets a critical state flag:

```javascript
const ErrorOverlay = require('react-error-overlay');

ErrorOverlay.startReportingRuntimeErrors({
  onError: () => {
    hadRuntimeError = true;
  },
});

```

This `hadRuntimeError` flag serves a vital purpose in the hot reloading lifecycle. When set to `true`, it signals that the application state may be corrupted. If a subsequent hot update is deemed unsafe, CRA forces a full page reload rather than attempting to patch the module.

### Hooking Into Global Error Handlers

Inside [`packages/react-error-overlay/src/index.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/index.js), the `startReportingRuntimeErrors` function imports `listenToRuntimeErrors` from [`listenToRuntimeErrors.js`](https://github.com/facebook/create-react-app/blob/main/listenToRuntimeErrors.js). This utility attaches listeners to three critical error sources:

- `window.onerror` for synchronous exceptions
- `window.onunhandledrejection` for unhandled Promise rejections
- The `ErrorUtils` global (used internally by React)

When any of these listeners fire, they create an **ErrorRecord** object containing the error instance, parsed stack frames, and context. This record passes to `handleRuntimeError`, which manages the UI state.

## Rendering Runtime Errors in the Error Overlay

Once captured, errors must be displayed in isolation from your application code to prevent the error UI itself from crashing. CRA achieves this by mounting the overlay inside a sandboxed iframe.

### Storing Errors and Updating the Iframe

The `handleRuntimeError` function (defined in [`packages/react-error-overlay/src/index.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/index.js) lines 83-100) executes the `onError` callback, deduplicates identical errors by checking `currentRuntimeErrorRecords`, and pushes the new record into that array. It then calls `update()`:

```javascript
function handleRuntimeError(options) {
  return function (errorRecord) {
    if (typeof options.onError === 'function') {
      options.onError();
    }
    if (currentRuntimeErrorRecords.some(r => r.error === errorRecord.error)) {
      return;
    }
    currentRuntimeErrorRecords.push(errorRecord);
    update();
  };
}

```

The `update()` function creates a hidden iframe on first run, loading `iframeScript` (a pre-bundled script containing the React UI). When the iframe signals readiness via `window.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__.iframeReady`, `updateIframeContent()` serializes the error records and passes them to `iframe.contentWindow.updateContent`.

### The React Component Hierarchy Inside the Iframe

Inside the iframe, the UI renders as a standard React component tree defined in [`packages/react-error-overlay/src/components/ErrorOverlay.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/components/ErrorOverlay.js) and related containers:

1. **`<ErrorOverlay>`** - The root component that handles keyboard shortcuts (Esc to close, arrow keys to navigate)
2. **`<RuntimeErrorContainer>`** - Manages state for multiple runtime errors, rendering navigation controls
3. **`<RuntimeError>`** - Displays individual error details using:
   - **`<Header>`** - Shows the error name and message
   - **`<StackTrace>`** - Renders clickable stack frames with the `editorHandler` callback

The `editorHandler` function, configured by CRA, allows users to click any stack frame to open their code editor directly to the offending line.

## Code Examples: Working with the Error Overlay

The following examples demonstrate how CRA initializes the overlay and how it processes runtime errors internally.

**Initializing the overlay in the development client:**

```javascript
// CRA’s dev client – registers the overlay (run automatically in `npm start`)
const ErrorOverlay = require('react-error-overlay');

ErrorOverlay.startReportingRuntimeErrors({
  onError: () => {
    // CRA sets a flag so the next successful compile forces a full reload
    hadRuntimeError = true;
  },
});

```

**Handling a runtime error internally:**

```javascript
// Inside react‑error‑overlay – how a runtime error is recorded
function handleRuntimeError(options) {
  return function (errorRecord) {
    if (typeof options.onError === 'function') {
      options.onError();               // CRA’s callback above
    }
    // Avoid duplicate entries
    if (currentRuntimeErrorRecords.some(r => r.error === errorRecord.error)) {
      return;
    }
    currentRuntimeErrorRecords.push(errorRecord);
    update();                           // triggers iframe re‑render
  };
}

```

**Rendering the error UI:**

```jsx
// The UI component that finally displays the error
function RuntimeError({ errorRecord, editorHandler }) {
  const { error, stackFrames } = errorRecord;
  const header = `${error.name}: ${error.message}`;
  return (
    <div style={wrapperStyle}>
      <Header headerText={header} />
      <StackTrace
        stackFrames={stackFrames}
        errorName={error.name}
        editorHandler={editorHandler}
      />
    </div>
  );
}

```

## Key Source Files for the Error Overlay

Understanding the error overlay architecture requires familiarity with these specific modules in the `facebook/create-react-app` repository:

- [`packages/react-dev-utils/webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-dev-utils/webpackHotDevClient.js) - Starts the overlay in development and coordinates HMR / reload logic
- [`packages/react-error-overlay/src/index.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/index.js) - Core API (`startReportingRuntimeErrors`, `reportRuntimeError`, iframe handling)
- [`packages/react-error-overlay/src/components/ErrorOverlay.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/components/ErrorOverlay.js) - Wrapper that renders the overlay and handles shortcut keys
- [`packages/react-error-overlay/src/containers/RuntimeErrorContainer.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js) - Manages navigation between multiple runtime errors
- [`packages/react-error-overlay/src/containers/RuntimeError.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/containers/RuntimeError.js) - Displays the error header and stack trace
- [`packages/react-error-overlay/src/utils/parseCompileError.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-error-overlay/src/utils/parseCompileError.js) - Parses stack frames for clickable "open in editor" links

## Summary

- **react-error-overlay** is a development-only UI injected by Create React App to catch and display runtime JavaScript errors.
- The overlay registers global listeners via `startReportingRuntimeErrors` in [`webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/webpackHotDevClient.js), capturing exceptions from `window.onerror`, `window.onunhandledrejection`, and React's `ErrorUtils`.
- Errors are stored as `ErrorRecord` objects in `currentRuntimeErrorRecords` and rendered inside an isolated iframe to prevent conflicts with application code.
- The UI consists of a React component hierarchy: `ErrorOverlay` → `RuntimeErrorContainer` → `RuntimeError` → `Header` and `StackTrace`.
- When a runtime error occurs, CRA sets `hadRuntimeError = true`, forcing a full page reload on the next successful compilation if the hot update is unsafe.

## Frequently Asked Questions

### How does Create React App catch runtime errors without modifying my source code?

CRA injects the `react-error-overlay` package through the webpack development client ([`webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/webpackHotDevClient.js)). This client automatically calls `ErrorOverlay.startReportingRuntimeErrors()` when the development server starts, attaching listeners to global browser error events like `window.onerror` and `window.onunhandledrejection`. Because this happens in the dev client's entry point, your application source code remains unchanged.

### Why does the error overlay use an iframe instead of rendering directly in the DOM?

The overlay renders inside a sandboxed iframe to achieve complete style and script isolation from your React application. This prevents CSS conflicts where your app's styles might accidentally hide or distort the error UI, and it ensures that if your application is in a broken state, the overlay can still function independently. The iframe loads a pre-bundled script that contains the React component tree for the error display.

### What happens after I fix a runtime error and save the file?

When you save a fix, CRA's webpack dev server detects the change and attempts a Hot Module Replacement (HMR). However, because a runtime error previously set `hadRuntimeError = true` in [`webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/webpackHotDevClient.js), CRA treats the application state as potentially corrupted. If the hot update is deemed unsafe or if the update fails, CRA automatically performs a full page reload to ensure your application starts from a clean state without any lingering error side effects.

### Can I customize the error overlay or disable it in development?

While CRA does not expose official configuration options to customize the overlay's appearance, you can disable it by ejecting from CRA or by using environment variables that prevent the dev client from starting the overlay. However, disabling it is generally not recommended because the overlay provides critical debugging information including clickable stack traces that open directly in your code editor. If you need custom error handling, you would typically eject and modify [`webpackHotDevClient.js`](https://github.com/facebook/create-react-app/blob/main/webpackHotDevClient.js) or fork `react-error-overlay`.