Back to Blog Home

Capture and report JavaScript errors with window.onerror

Ben Vinegar image

Ben Vinegar - Last Updated:

Capture and report JavaScript errors with window.onerror

Capture and report JavaScript errors with window.onerror

ON THIS PAGE

The window.onerror event handler is a special browser event handler that fires whenever an uncaught JavaScript error has been thrown. It’s one of the easiest ways to log client-side errors and report them to your servers. It’s also one of the major mechanisms by which the Sentry JavaScript SDK works under the hood.

You listen to the onerror event by assigning a function to window.onerror:

Click to Copy
window.onerror = function (msg, url, lineNo, columnNo, error) {
  console.log('Error message: ', msg);
  console.log('URL: ', url);
  console.log('Line: ', lineNo);
  console.log('Column: ', columnNo);
  console.log('Error object: ', error);

  return true; // Prevents the default browser error handling
};

When an error is thrown, the following arguments are passed to the function:

  • msg adds the message associated with the error. For example, Uncaught ReferenceError: foo is not defined in Chrome or Can’t find variable: foo in Safari.

  • url adds the URL of the script or document associated with the error. For example, /dist/app.js.

  • lineNo adds the line number (if available).

  • columnNo adds the column number (if available).

  • error adds the Error object associated with this error (if available).

The first four arguments tell you in which script, line, and column the error occurred. The final argument, the Error object, is perhaps the most valuable. Let’s learn why.

The Error object and stack traces

At first glance, the Error object isn’t very special. It contains three properties - message, fileName, and lineNumber — redundant values that are already provided to you via window.onerror.

The valuable part is a non-standard property: Error.prototype.stack. This stack property tells you the source location of each frame in the call stack when the error occurred.

Click to Copy
function foo() {
  bar();
}

function bar() {
  throw new Error('Something went wrong!');
}

try {
  foo();
} catch (e) {
  console.log(e.stack);
}

In Chrome, the stack trace might look like this:

Click to Copy
Error: Something went wrong!
  at bar (file:///path/to/script.js:42:15)
  at foo (file:///path/to/script.js:38:5)
  at file:///path/to/script.js:44:5

Once it’s been formatted, it’s easy to see how the stack property can be critical for debugging an error.

There’s just one snag: The stack property is non-standard, and its implementation differs across browsers. For example, here’s the same stack trace from Safari:

Click to Copy
Error: Something went wrong!
  bar@file:///path/to/script.js:42:15
  foo@file:///path/to/script.js:38:5
  global code@file:///path/to/script.js:44:5

Not only is the format of each frame different (Safari uses @ while Chrome uses at), but the frames also have different levels of detail. For example, Chrome identifies that the new keyword has been used and has greater insight into eval invocations. Different browsers have varying formats and detail levels.

Handling promise rejections

Today’s JavaScript applications rely heavily on Promise objects and async/await syntax. Unhandled Promise rejections don’t trigger window.onerror but instead fire a different event:

Click to Copy
window.addEventListener('unhandledrejection', function(event) {
  console.log('Unhandled promise rejection:', event.reason);
  console.log('Promise:', event.promise);

  // Optional: prevent the default console.error behavior
  event.preventDefault();
});

// This will trigger the unhandledrejection handler
Promise.reject(new Error('Async operation failed'));

Both window.onerror and unhandledrejection are essential for comprehensive error coverage.

Browser compatibility

Modern browsers universally support all five arguments, including the crucial Error object that contains the stack trace. Legacy browsers (such as Internet Explorer 8-10 and older Safari versions) had limited support, but these browsers now represent less than 1% of global usage and can generally be ignored for new applications.

While Safari supports all five arguments, it may return generic Script error. messages with limited details in window.onerror for certain types of errors, especially those from cross-origin scripts. The Error object’s stack trace is still available when the full Error object is accessible.

Why manual error handling is mostly obsolete

While understanding window.onerror is educational, manually implementing error reporting today is largely unnecessary. Modern error monitoring SDKs like Sentry automatically:

  • Set up window.onerror and unhandledrejection handlers

  • Normalize stack traces across browsers

  • Handle cross-origin script errors

  • Instrument async code (such as fetch, setTimeout, and event listeners)

  • Provide rich context (including user actions, breadcrumbs, and performance data)

Here’s how you can use Sentry to capture errors.

Using npm and other module bundlers:

Click to Copy
import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "YOUR_DSN_HERE",
  integrations: [
    Sentry.browserTracingIntegration(),
  ],
  tracesSampleRate: 1.0,
  environment: "production",
});

// Here's a basic example of how to capture errors in try/catch blocks:
try {
  riskyOperation();
} catch (error) {
  Sentry.captureException(error);
}
Using a CDN:
<script
  src="https://js-de.sentry-cdn.com/YOUR_PROJECT_PUBLIC_KEY.min.js"
  crossorigin="anonymous"
></script>
<script>
  Sentry.init({
    dsn: "YOUR_DSN_HERE",
    tracesSampleRate: 1.0,
    environment: "production",
  });
</script>

Now, you can use the Sentry JavaScript SDK to capture errors.

Risky operation failed in Sentry

Note: The basic CDN bundle includes error tracking but not performance monitoring. For tracing features like Sentry.startSpan(), use the tracing bundle or npm package.

Transmitting errors to your server (if you still need to)

If you’re building custom error handling, you’ll need to transmit error data to your server. Let’s use the Fetch API to do that:

Click to Copy
async function reportError(errorData) {
  try {
    await fetch('/api/errors', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        message: errorData.message,
        stack: errorData.stack,
        url: window.location.href,
        userAgent: navigator.userAgent,
        timestamp: new Date().toISOString(),
      }),
    });
  } catch (e) {
    // Silently fail - don't throw errors in error handling
    console.warn('Failed to report error:', e);
  }
}

window.onerror = function (msg, url, lineNo, columnNo, error) {
  reportError({
    message: msg,
    stack: error?.stack,
    url: url,
    line: lineNo,
    column: columnNo,
  });

  return true;
};

The Sentry JavaScript SDK automatically:

  • Captures unhandled errors and Promise rejections

  • Normalizes stack traces across browsers

  • Provides source map support for debugging minified code

  • Offers performance monitoring and release tracking

  • Includes user context and custom tags

  • Handles error deduplication and rate limiting

Summary

While you can build basic error reporting yourself, modern applications benefit from using established tools, like the Sentry JavaScript SDK, which handle the complexities of cross-browser compatibility, error deduplication, performance monitoring, and rich debugging context.

Ready to get started with professional JavaScript error monitoring? Try Sentry’s JavaScript SDK for comprehensive error tracking and performance monitoring.

FAQs

Share

Share on Twitter
Share on Bluesky
Share on HackerNews
Share on LinkedIn

Last Updated

Sentry Sign Up CTA

Code breaks, fix it faster

Sign up for Sentry and monitor your application in minutes.

Try Sentry Free

Topics

Error Monitoring
How Anthropic solved scaling log volume with Sentry

How Anthropic solved scaling log volume with Sentry

Listen to the Syntax Podcast

Of course we sponsor a developer podcast. Check it out on your favorite listening platform.

Listen To Syntax
© 2025 • Sentry is a registered Trademark of Functional Software, Inc.