Skip to main content

Frontend Error Tracking

Capturing, analyzing, and debugging JavaScript errors using agnt's proxy.

Overview​

The proxy automatically captures:

  • Uncaught exceptions - window.onerror
  • Unhandled promise rejections - unhandledrejection events
  • Custom errors - Via window.__devtool.error()

All errors include stack traces, source locations, and page context.

Viewing Captured Errors​

Query Error Logs​

proxylog {proxy_id: "app", types: ["error"]}
→ {
entries: [
{
type: "error",
timestamp: "2024-01-15T10:32:15Z",
message: "Cannot read property 'map' of undefined",
source: "http://localhost:8080/static/js/main.js",
line: 142,
column: 23,
stack: "TypeError: Cannot read property 'map' of undefined\n at UserList (main.js:142:23)\n at renderWithHooks...",
url: "http://localhost:8080/users",
userAgent: "Mozilla/5.0..."
}
]
}

Filter by Time​

// Errors in the last 5 minutes
proxylog {proxy_id: "app", types: ["error"], since: "5m"}

// Errors in a specific window
proxylog {proxy_id: "app", types: ["error"], since: "2024-01-15T10:00:00Z", until: "2024-01-15T11:00:00Z"}

Get Error Statistics​

proxylog {proxy_id: "app", action: "stats"}
→ {
by_type: {
http: 1500,
error: 12,
performance: 45
}
}

Correlating Errors with Traffic​

Find What API Calls Preceded an Error​

// Get error timestamp
proxylog {proxy_id: "app", types: ["error"]}
→ Error at 10:32:15 on /users page

// Check API calls around that time
proxylog {
proxy_id: "app",
types: ["http"],
url_pattern: "/api",
since: "2024-01-15T10:32:00Z",
until: "2024-01-15T10:32:20Z"
}
→ {
entries: [
{url: "/api/users", status: 500, response_body: "{\"error\": \"...\"}", timestamp: "10:32:14"}
]
}

The API returned 500, causing the subsequent JavaScript error.

Use Page Sessions​

// Get page session that had errors
currentpage {proxy_id: "app"}
→ {sessions: [{id: "page-1", error_count: 2, url: "/users"}]}

// Get full context
currentpage {proxy_id: "app", action: "get", session_id: "page-1"}
→ {
resources: [
{url: "/api/users", status: 500}
],
errors: [
{message: "Cannot read property 'map'..."}
],
performance: {...}
}

Debugging Specific Errors​

Inspect Error Location​

// From error log, we know the component is UserList at line 142
// Inspect the component in the browser

proxy {action: "exec", id: "app", code: "window.__devtool.inspect('.user-list')"}
→ {
element: {tag: "div", classes: ["user-list"]},
visibility: {visible: true},
// Check if element rendered at all
}

Check Application State​

// What's in localStorage/sessionStorage?
proxy {action: "exec", id: "app", code: "window.__devtool.captureState(['localStorage', 'sessionStorage'])"}

// Check for cached data
→ {
localStorage: {users: null}, // Expected to have user data
sessionStorage: {}
}

Reproduce the Error​

// Wait for the problematic component
proxy {action: "exec", id: "app", code: "window.__devtool.waitForElement('.user-list', 10000)"}

// If it never appears, the error prevented rendering

Custom Error Logging​

Log from Application Code​

// In your application code
try {
await fetchUsers();
} catch (error) {
window.__devtool?.error('Failed to fetch users', {
error: error.message,
stack: error.stack,
userId: currentUser.id
});
}

Query Custom Logs​

proxylog {proxy_id: "app", types: ["custom"]}
→ {
entries: [
{
level: "error",
message: "Failed to fetch users",
data: {error: "Network error", userId: 123},
timestamp: "..."
}
]
}

Error Monitoring Patterns​

Real-Time Error Watch​

// Check for new errors periodically
proxylog {proxy_id: "app", types: ["error"], since: "1m"}

Error Grouping​

proxy {action: "exec", id: "app", code: `
// Group errors by message (simplified)
const logs = await fetch('/__devtool_api/errors').then(r => r.json());
const grouped = {};

logs.forEach(err => {
const key = err.message.replace(/\\d+/g, 'N'); // Normalize numbers
grouped[key] = grouped[key] || {count: 0, examples: []};
grouped[key].count++;
if (grouped[key].examples.length < 3) {
grouped[key].examples.push(err);
}
});

grouped
`}

Error Rate Tracking​

// Check error count
proxylog {proxy_id: "app", action: "stats"}
→ {by_type: {error: 12}}

// Compare to traffic
// If 12 errors in 1500 requests = 0.8% error rate

Handling Specific Error Types​

Uncaught Exceptions​

proxylog {proxy_id: "app", types: ["error"]}
→ {
message: "TypeError: Cannot read property 'x' of undefined",
source: "main.js",
line: 100
}

Debug approach:

  1. Check the source file and line
  2. Inspect variables at that location
  3. Check API responses that might have returned unexpected data

Promise Rejections​

→ {
message: "Unhandled Promise Rejection: NetworkError",
source: "api.js",
line: 45
}

Debug approach:

  1. Check network logs for failed requests
  2. Add .catch() handlers to promises
  3. Check if network was available

Syntax Errors​

→ {
message: "SyntaxError: Unexpected token '<'",
source: "app.js",
line: 1
}

This usually means:

  • JS file returned HTML (404 page)
  • Build error produced invalid JS
  • Script src is wrong

Check:

proxylog {proxy_id: "app", types: ["http"], url_pattern: "app.js"}
→ Check Content-Type and response body

Creating Error Reports​

Capture Error Context​

// When error is reported:

// 1. Screenshot
proxy {action: "exec", id: "app", code: "window.__devtool.screenshot('error-state')"}

// 2. DOM state
proxy {action: "exec", id: "app", code: "window.__devtool.captureDOM()"}

// 3. Application state
proxy {action: "exec", id: "app", code: "window.__devtool.captureState(['localStorage'])"}

// 4. Recent network
proxy {action: "exec", id: "app", code: "window.__devtool.captureNetwork()"}

// 5. Error details
proxylog {proxy_id: "app", types: ["error"], limit: 5}

Automated Error Report​

proxy {action: "exec", id: "app", code: `
const report = {
timestamp: new Date().toISOString(),
url: window.location.href,
userAgent: navigator.userAgent,
viewport: {
width: window.innerWidth,
height: window.innerHeight
},
state: window.__devtool.captureState(['localStorage']),
recentErrors: [], // Would need API call to get these
screenshot: await window.__devtool.screenshot('error-report')
};

JSON.stringify(report, null, 2)
`}

Integration with Error Tracking Services​

Send to External Service​

// In your app, forward errors
window.addEventListener('error', (event) => {
// Log to devtool
window.__devtool?.log(event.message, 'error', {
source: event.filename,
line: event.lineno
});

// Also send to Sentry/Datadog/etc
Sentry.captureException(event.error);
});

Compare with Production​

// Proxy captures same data as production error tracking
// Use for debugging before errors reach production

Best Practices​

  1. Always check errors first - Many bugs start with JS errors
  2. Correlate with API calls - Errors often caused by bad data
  3. Use page sessions - See full context of error
  4. Capture state - localStorage, DOM, network
  5. Screenshot - Visual state at error time
  6. Check console too - Some errors only in console

Common Error Patterns​

ErrorLikely CauseDebug Steps
undefined is not a functionMethod on nullCheck API response
Cannot read property XNull referenceTrace data flow
Network ErrorCORS, offline, 500Check HTTP logs
Unexpected token <HTML instead of JSCheck Content-Type
Script error.Cross-origin scriptCheck CORS headers

See Also​