Global Error Handling in JavaScript
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list ESLint and Sentry, but missing unhandledrejection listeners or silent promise rejections are not caught by default ESLint rules — they require specialist configuration or a runtime monitoring service like Sentry to observe in production. The absence of a global handler is invisible until real users hit uncaught errors, placing this closer to d7 than d5.
Closest to 'simple parameterised fix' (e3). The quick_fix is clear: add both window.onerror and window.addEventListener('unhandledrejection') handlers that POST to a PHP endpoint or Sentry. This is a small, localised change — a new error-handling module wired up in one place — but it may touch configuration, endpoint setup, and rate-limiting logic, putting it slightly above a one-liner (e1) at e3.
Closest to 'localised tax' (b3). The applies_to scope is web only, and the handler itself is a centralised setup (one file/module). However, once added it affects how all async code and promise chains should be written going forward (correlating with session IDs, rate-limiting reports), imposing a modest ongoing tax on maintainers without being truly cross-cutting.
Closest to 'serious trap' (t7). The misconception field explicitly states that developers believe console.error() is sufficient for production error tracking, when in reality it only logs to DevTools and is invisible to server-side monitoring. This contradicts intuitive expectations — console.error looks like error reporting but is not. Combined with the common mistake of missing unhandledrejection for Promises, this is a well-documented but frequently encountered serious trap.
Also Known As
TL;DR
Explanation
window.onerror catches synchronous errors. window.addEventListener('unhandledrejection') catches unhandled Promise rejections. Both should log to your PHP error tracking endpoint. Error.cause (ES2022) chains errors. window.reportError() programmatically triggers error handlers. In React: ErrorBoundary components catch render errors. Always include: message, stack, URL, line, user context, and PHP session ID for correlation. Never expose internal paths in production error messages.
Common Misconception
Why It Matters
Common Mistakes
- Only using try/catch locally — missing unhandled Promise rejections
- Not correlating JS errors with PHP session ID or request ID
- Sending error reports on every error — should rate-limit and batch
Code Examples
// Only catches sync errors, misses promise rejections:
window.onerror = (msg) => console.error(msg);
// Comprehensive global handler reporting to PHP:
function reportError(error, context = {}) {
navigator.sendBeacon('/api/errors', JSON.stringify({
message: error.message,
stack: error.stack,
url: location.href,
context: { ...context, sessionId: window.__phpSessionId },
}));
}
window.onerror = (msg, src, line, col, err) => {
reportError(err ?? new Error(msg), { src, line, col });
};
window.addEventListener('unhandledrejection', (e) => {
reportError(e.reason instanceof Error ? e.reason : new Error(e.reason));
});