Fall back to ErrorEvent.message in special-pages error handlers#2714
Fall back to ErrorEvent.message in special-pages error handlers#2714noisysocks wants to merge 2 commits into
Conversation
Cross-origin script errors fire with event.error=null but useful info in event.message. The old handler discarded that and reported '[uncaught] unknown error', which is what produced the m_mac_onboarding_exception-reported spike on macOS 1.190.0. Also simplify the rejection handler so falsy reasons (undefined, null, 0) report distinct messages instead of all bucketing to 'unknown'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build Branch
Static preview entry points
QR codes (mobile preview)
Integration commandsnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "pr-releases/randerson/special-pages-error-handler-fallback")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/randerson/special-pages-error-handler-fallback
git -C submodules/content-scope-scripts checkout origin/pr-releases/randerson/special-pages-error-handler-fallbackPin to exact commitnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "0870971e5b01e61cbd2dd2c569b82d1cad85b89a")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/randerson/special-pages-error-handler-fallback
git -C submodules/content-scope-scripts checkout 0870971e5b01e61cbd2dd2c569b82d1cad85b89a |
[Beta] Generated file diffTime updated: Mon, 25 May 2026 09:45:43 GMT Apple
File has changed Integration
File has changed Windows
File has changed |
There was a problem hiding this comment.
Stale comment
Web Compatibility Assessment
No web-compat findings.
special-pages/pages/history/src/index.js:86-93,special-pages/pages/new-tab/src/index.js:113-120,special-pages/pages/onboarding/app/index.js:40-47- info: the changed listeners only affect diagnostic reporting for special pages. They do not wrap/shim browser APIs, alter prototypes/descriptors, mutate the DOM, or change injected page-world behavior.- Same ranges - info: existing integration tests cover
throw new Error(...)andPromise.reject(new Error(...)); the newErrorEvent.messageand primitive rejection fallback paths are manually verified but not covered by automated tests.Security Assessment
No security findings.
- Same ranges - info: the outgoing payload remains a literal
reportInitExceptionmessage; there is nonativeDataspreading, message bridge change, origin validation change, new network request,postMessage, or privileged data exposure. This is special-page app code, not hostile page-world injected code.Risk Level
Low Risk - limited to three special-page global error/rejection diagnostic handlers, with no injected runtime, wrapper utility, captured-global, or messaging transport changes.
Recommendations
- Non-blocking: add explicit integration coverage for
new ErrorEvent('error', { message: 'Script error.', error: null })and primitive/nullish rejection reasons (undefined,null,0) in the existing global error listener suites so the new fallback behavior does not regress.Sent by Cursor Automation: Web compat and sec
shakyShane
left a comment
There was a problem hiding this comment.
If it's provable in a console snippet, could you add a playwright test to at least one of these?
Dismissing stale approval — new commits pushed, awaiting Cursor re-review.
d208bc7 to
751431f
Compare
Dismissing stale approval — new commits pushed, awaiting Cursor re-review.
There was a problem hiding this comment.
Stale comment
Web Compatibility Assessment
No web-compat findings.
special-pages/pages/history/src/index.jslines 86-93,special-pages/pages/new-tab/src/index.jslines 113-120,special-pages/pages/onboarding/app/index.jslines 40-47 - info: the changed global error/rejection listeners only affect diagnostic reporting in special pages. They do not wrap or shim browser APIs, alter prototypes/descriptors, mutate page DOM, or change injected page-world behavior.special-pages/pages/onboarding/integration-tests/onboarding.v4.spec.jslines 855-891 - info: the previously missing fallback coverage is now present for cross-origin-styleErrorEventobjects witherror: nulland for primitive/nullish rejection reasons.Security Assessment
No security findings.
- Same handler ranges - info: the outgoing
reportInitExceptionpayload remains a literal message object/string and does not spread untrusted objects, includenativeData, addpostMessage, change origin validation, or touch the message bridge. The template-literal callsites preserve themessage: stringcontract before data crosses the special-page native messaging boundary.Risk Level
Low Risk - limited to special-page diagnostic fallback logic and targeted Playwright coverage, with no injected runtime, wrapper utility, captured-global, or messaging transport changes.
Recommendations
No blocking recommendations.
Validation:
npm run test-int -- pages/onboarding/integration-tests/onboarding.v4.spec.js --grep "global error listeners" --reporter listpassed (10 passed).Sent by Cursor Automation: Web compat and sec
There was a problem hiding this comment.
Web Compatibility Assessment
No web-compat findings.
special-pages/pages/history/src/index.js:86-93,special-pages/pages/new-tab/src/index.js:113-120,special-pages/pages/onboarding/app/index.js:40-47- info: the changed listeners only affect diagnostic error reporting in special pages. They do not wrap/shim browser APIs, alter prototypes/descriptors, mutate DOM structure, or affect injected page-world behavior.special-pages/pages/onboarding/integration-tests/onboarding.v4.spec.js:855-889- info: the synchronized update adds automated coverage for the previously notedErrorEvent.messagefallback and primitive/nullish rejection reasons.
Security Assessment
No security findings.
- Same handler ranges - info: outgoing messages remain literal
reportInitExceptionpayloads with only a stringifiedmessage; there is nonativeDataspreading, message bridge change, origin-validation relaxation, new network request,postMessage, or privileged data exposure.
Risk Level
Low Risk - limited to special-page diagnostic handlers and targeted onboarding integration tests, with no injected runtime, wrapper utility, captured-global, or messaging transport changes.
Recommendations
No blocking recommendations. Targeted validation passed: npm run test-int -- --grep "global error listeners" --reporter list from special-pages/ (16 passed).
Sent by Cursor Automation: Web compat and sec
Covers the cross-origin ErrorEvent shape (error=null) that produced the production pixel, and the primitive/nullish rejection reasons (undefined, null, 0) that previously all bucketed to 'unknown rejection'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
751431f to
ca9c960
Compare
|
This PR requires a manual review and approval from a member of one of the following teams:
|


Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1207340338530322/task/1215001863923847
Description
The
window.addEventListener('error', …)handlers in onboarding, new-tab, and history all readevent.error?.messageand fell through to'unknown error'whenevent.errorwas null. That's the case for cross-origin script errors, some resource load failures, andthrow undefined—ErrorEvent.messagestill has useful info (e.g."Script error.") in those cases. The old code discarded it.This produced the
m_mac_onboarding_exception-reportedspike on macOS 1.190.0 (message=[uncaught] unknown error, empty id) — the pixel landed in native but the JS side already lost everything diagnostic.Fix:
event.error?.message || event.message || 'unknown error'. Same change applied to all three special pages so they don't drift.While there, simplify the
unhandledrejectionhandler toevent.reason?.message || String(event.reason)— same shape, andPromise.reject(undefined / null / 0)now report distinct messages (undefined,null,0) instead of all collapsing to'unknown rejection'.Testing Steps
Open any of the three pages in a browser (swap
new-tabforonboardingorhistory):Open devtools console.
Paste this snippet and hit enter — it captures the native-bound notifications, fires every error/rejection shape we care about, and prints what the JS would send to native:
You should see (the second line is the actual production bug being fixed):
Before this PR, the "cross-origin shape" line would have read
[uncaught] unknown error, and the three falsyPromise.rejectlines would all have read[unhandledrejection] unknown rejection.Checklist
Please tick all that apply:
Note
Low Risk
Telemetry-only message formatting in page bootstrap listeners; no auth, data, or user-facing behavior changes beyond clearer exception text sent to native.
Overview
Special-pages onboarding, new-tab, and history now build uncaught error reports from
event.error?.message, thenevent.message, then a fallback—so cases like cross-originErrorEventshapes (error: null, message still set) no longer collapse to[uncaught] unknown error.Unhandled rejection reporting uses
event.reason?.message || String(event.reason)so non-Errorreasons (e.g.undefined,null,0) send distinct native messages instead of a generic unknown string.Onboarding integration tests cover the
ErrorEvent.messagefallback and those rejection shapes.Reviewed by Cursor Bugbot for commit ca9c960. Bugbot is set up for automated code reviews on this repo. Configure here.