Skip to content

Commit 3baebd4

Browse files
iskounenclaude
andauthored
feat: add comprehensive global error tracking for "Load failed" debugging (#15963)
- Add global error handlers for resource loading failures (scripts, images, CSS) - Track unhandled promise rejections for network errors - Capture detailed error context including resource URLs, types, and element HTML - Integrate error tracking into client initialization - Document future enhancement opportunities for fetch tracking, CSP violations, etc. This addresses the #1 Sentry issue by providing visibility into all types of resource loading failures across the application. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <[email protected]>
1 parent 0e3602f commit 3baebd4

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { captureException } from "@sentry/browser"
2+
3+
export function setupGlobalErrorHandlers() {
4+
// Handle resource loading failures (scripts, images, stylesheets, etc.)
5+
window.addEventListener(
6+
"error",
7+
event => {
8+
const target = event.target as
9+
| (HTMLElement & { src?: string; href?: string })
10+
| null
11+
12+
// Only track resource loading errors, not JavaScript runtime errors
13+
if (target && target !== (window as any)) {
14+
const resourceUrl = target.src || target.href || "unknown"
15+
const resourceType = target.tagName?.toLowerCase() || "unknown"
16+
17+
captureException(
18+
new Error(`Resource load failed: ${event.message || "Load failed"}`),
19+
{
20+
tags: {
21+
source: "resource_load_failure",
22+
resource_type: resourceType,
23+
},
24+
extra: {
25+
resourceUrl,
26+
resourceType,
27+
errorMessage: event.message,
28+
filename: event.filename,
29+
lineno: event.lineno,
30+
colno: event.colno,
31+
targetElement: target.outerHTML,
32+
},
33+
},
34+
)
35+
}
36+
},
37+
// Use capture phase to catch all resource errors
38+
true,
39+
)
40+
41+
// Handle unhandled promise rejections (network failures, etc.)
42+
window.addEventListener("unhandledrejection", event => {
43+
const reason = event.reason
44+
45+
// Check if it's a network-related error
46+
if (
47+
reason instanceof Error &&
48+
(reason.message.includes("Load failed") ||
49+
reason.message.includes("Failed to fetch") ||
50+
reason.message.includes("Network request failed") ||
51+
reason.name === "NetworkError")
52+
) {
53+
captureException(reason, {
54+
tags: {
55+
source: "network_failure",
56+
error_type: "unhandled_rejection",
57+
},
58+
extra: {
59+
promiseRejectionReason: reason.message,
60+
stack: reason.stack,
61+
},
62+
})
63+
}
64+
})
65+
66+
// TODO: Consider adding additional error tracking in follow-up PRs:
67+
// - Fetch tracking (safer alternatives: interceptor library, wrapper function, Service Worker)
68+
// - CSP violations: addEventListener("securitypolicyviolation") for blocked resources
69+
// - Network connectivity: addEventListener("offline/online") for connection issues
70+
// - Chunk loading failures: track dynamic import() errors for code splitting
71+
// - Service Worker errors: track SW registration/update failures
72+
// - WebSocket connection failures: track real-time connection issues
73+
// - Media loading errors: track video/audio loading failures if relevant
74+
}

src/client.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { setupAnalytics } from "Server/analytics/helpers"
44
import { getOrInitUnleashClient } from "System/FeatureFlags/unleashClient"
55
import { setupClientRouter } from "System/Router/clientRouter"
66
import { setupSentryClient } from "System/Utils/setupSentryClient"
7+
import { setupGlobalErrorHandlers } from "System/Utils/setupGlobalErrorHandlers"
78
import { setupWebVitals } from "System/Utils/setupWebVitals"
89
import { hydrateRoot } from "react-dom/client"
910
import { getAppRoutes } from "routes"
1011

1112
setupAnalytics()
1213
setupSentryClient()
14+
setupGlobalErrorHandlers()
1315
setupWebVitals()
1416

1517
// Rehydrate app

0 commit comments

Comments
 (0)