JavaScript Global Error Handling and Runtime Exceptions

The global error event acts as the final safety net in browser environments, capturing unhandled runtime exceptions that bubble up from different scripts, asynchronous callbacks, and dynamically loaded modules. By listening to the global error event via window.onerror or window.addEventListener('error'), developers can log, monitor, and gracefully handle uncaught errors throughout the entire lifecycle of a web application without wrapping every execution block in individual try...catch statements.

The Mechanism of Global Error Bubbling

When a JavaScript engine encounters an unhandled runtime error—such as a TypeError or ReferenceError—the error propagates up the call stack. If no active try...catch block intercepts the exception, it reaches the global execution context (window in browsers, or globalThis in modern environments).

At this global boundary, the browser triggers the global error event, passing critical metadata regarding the failure to any registered global handlers.

Implementing Global Error Listeners

There are two primary methods to listen for global runtime errors:

1. window.onerror

The traditional approach assigns a callback function directly to window.onerror. This callback receives five distinct parameters:

window.onerror = function (message, source, lineno, colno, error) {
  console.error("Caught globally:", {
    message,
    source,
    lineno,
    colno,
    errorObject: error
  });
  
  // Returning true prevents the default browser error output in the console
  return true;
};

2. window.addEventListener('error')

The modern approach uses the standard DOM Level 2 event listener model, which receives a single ErrorEvent object containing the error properties:

window.addEventListener('error', function (event) {
  console.error("Runtime exception captured:", {
    message: event.message,
    filename: event.filename,
    lineno: event.lineno,
    colno: event.colno,
    error: event.error
  });
});

Capturing Across Different Script Types

The global error event operates across multiple script boundaries within the same document context:

(Note: Unhandled promise rejections do not trigger the error event directly; they require the unhandledrejection event listener).

Handling Cross-Origin Script Restrictions

To prevent malicious cross-origin information leaks, browsers enforce the Same-Origin Policy on error details. If a script hosted on an external domain (such as a CDN) throws an exception, the global handler will report a generic "Script error." with a line and column number of 0, omitting the error object and stack trace.

To allow the global error handler to capture full diagnostic details from external scripts, two requirements must be met:

  1. CORS Header on the Server: The server hosting the script must include the Access-Control-Allow-Origin: * (or your specific origin) HTTP response header.
  2. The crossorigin Attribute: The HTML <script> tag must declare the crossorigin attribute:
<script src="https://cdn.example.com/app.js" crossorigin="anonymous"></script>

Capturing Resource Loading Errors

The window.onerror handler only intercepts script runtime exceptions. When static resources (such as <img>, <link>, or <script> tags) fail to load over the network, they emit an error event targeted directly at the resource element.

These resource errors do not bubble up to window, but they can still be captured globally by setting the useCapture parameter to true on addEventListener:

window.addEventListener('error', function (event) {
  // Distinguish between resource loading errors and runtime exceptions
  if (event.target && (event.target.src || event.target.href)) {
    console.warn("Resource failed to load:", event.target);
  }
}, true); // Event capturing phase enables interception