How the Create React App Error Overlay Displays Runtime Errors

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. During initialization, this file calls ErrorOverlay.startReportingRuntimeErrors() with a callback that sets a critical state flag:

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, the startReportingRuntimeErrors function imports listenToRuntimeErrors from 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 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():

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 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:

// 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:

// 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:

// 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:

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, 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: ErrorOverlayRuntimeErrorContainerRuntimeErrorHeader 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). 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, 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 or fork react-error-overlay.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →