Skip to content

fix: Sentry audit — crash fixes, 404s for bot traffic, hydration and noise routing - #1360

Open
tyhonchik wants to merge 7 commits into
mainfrom
fix/sentry-audit-hardening
Open

fix: Sentry audit — crash fixes, 404s for bot traffic, hydration and noise routing#1360
tyhonchik wants to merge 7 commits into
mainfrom
fix/sentry-audit-hardening

Conversation

@tyhonchik

@tyhonchik tyhonchik commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

This fixes what a Sentry audit of app-next production surfaced: four real crash classes, a bot-traffic class that failed server renders instead of serving 404s, and a set of environment-noise patterns polluting the error stream. Previously the top unclassified issues were hydration mismatches (~200 events/14d), bot-probed dead URLs reported as server errors (~250 events), and in-app-browser junk (~150 events) — drowning out the genuine crashes hiding among them. Now each class is either fixed at the source or routed through the existing noise_class taxonomy — the unclassified error stream is left for actual bugs.

Changes

  • Lock-to-vote crash on SPP sub-proposals (APP-NEXT-2ES, escalating). SPP evaluates a body through the stage plugin's interface type, but the tokensTotalSupply enrichment keyed off the sub-proposal's own pluginInterfaceType — a sub-proposal with inconsistent backend data reached lockToVoteProposalUtils without the enrichment and crashed the whole proposals page with Cannot read properties of undefined (reading '0xe703…'). Enrichment now also matches by stage body address, and getProposalTokenTotalSupply tolerates missing data (tokensTotalSupply is typed optional).
  • Create routes crash on unknown plugin addresses (APP-NEXT-2EX, APP-NEXT-2EP). createProposalPageClient, createProcessPageClient and useProposalPermissionCheckGuard destructured useDaoPlugins(...)![0] unconditionally, so a direct load with an unknown or uninstalled pluginAddress crashed both server- and client-side. They now use safe access and render the standard Page.Error not-found state; the permission guard skips its check until the plugin resolves.
  • 404s instead of reported errors for bot-probed URLs (APP-NEXT-248, APP-NEXT-2CF, APP-NEXT-2CE, APP-NEXT-2D9, APP-NEXT-24C, APP-NEXT-24D). The members/proposals/proposal-details pages fetched the DAO with no error handling, so HEAD/GET bots hitting dead DAO addresses (including one with a trailing %20) produced Error: Not found / Error: Bad parameters server errors — ~250 Sentry events/14d with zero users. A new notFoundUtils.fetchOrNotFound maps backend 4xx on URL-addressed lookups to notFound(), the metadata utils suppress the same class, and onRequestError skips expected not-found codes. Real users with stale links now get a proper 404 page instead of a generic error.
  • Hydration mismatches from timezone-dependent dates (APP-NEXT-267, APP-NEXT-155, APP-NEXT-1YB, APP-NEXT-22, ~230 events/14d). formatterUtils.formatDate renders in the viewer's timezone (RELATIVE additionally recomputes against "now") while Vercel renders in UTC, so members/proposals/proposal-details/dashboard hydrated different text than the server sent whenever a timestamp crossed a UTC boundary. Those values are now gated behind useIsMounted, following the existing daoProcessDetailsPageClient pattern. Relative dates rendered inside gov-ui-kit's ProposalDataListItem have the same issue and need a kit-side follow-up.
  • Case-sensitive daoAddress filter dropped plugins client-side (APP-NEXT-2B9). With linked accounts off, useDaoPlugins compared plugin.daoAddress === dao.address by strict string equality while the server-side filter didn't — a checksum mismatch between the two backend fields emptied the plugin list only on the client and crashed pages dereferencing plugins[0] (gauge voter). The comparison is now case-insensitive.
  • Environment noise routed as expected (APP-NEXT-2B5, APP-NEXT-2D1, APP-NEXT-272, APP-NEXT-29W, APP-NEXT-2ED, APP-NEXT-2EZ). New environmentNoisePatterns list in monitoringUtils.beforeSend: WKWebView in-app-browser scripts stringify-ing cyclic structures (100% of APP-NEXT-2B5 events are WKWebView with zero app frames), wallet extensions fighting over window.ethereum, extensions mutating the DOM behind React, private-mode indexedDB, deploy skew and aborted streaming responses — plus AppKit's Failed to disconnect as expected wallet behaviour. Kept searchable in Sentry, tagged expected, demoted to info — routed, not dropped.
  • AragonBackendServiceError now sets this.name, so Sentry issue titles read AragonBackendServiceError: Bad parameters instead of a bare Error: ….

Note

Deliberately untouched: transactionDialog: transaction confirmation timed out (APP-NEXT-2E1) is an intentional warning-level signal for stuck-transaction monitoring; RPC/backend failures stay in the infra class. The generic Chrome cyclic-JSON message (no __reactFiber) still surfaces untagged so a genuine serialization bug of ours is never hidden — only the Safari/WKWebView variant is demoted. APP-NEXT-2DS/2DQ/20D last fired on releases ≤1.36 and should be resolved in Sentry after this deploys if they stay quiet; the gauge-voter client still dereferences plugins[0] without a guard (stale issue, root cause fixed here) — a defensive rewrite of that page is a separate follow-up.

🤖 Generated with Claude Code

@tyhonchik
tyhonchik requested a review from a team as a code owner September 1, 2026 12:46
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

🚀 Preview Deployment: View Here

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

E2E results (preview)

Smoke

Base URL https://app-next-2k42ntuga-aragon-app.vercel.app
Suite smoke
Playwright result ✅ passed
Summary 82 passed
HTML report View report
GitHub job ✅ completed

View run #5108

@linear-code

linear-code Bot commented Sep 1, 2026

Copy link
Copy Markdown

APP-1130

Comment thread apps/app/src/shared/api/aragonBackendService/aragonBackendServiceError.ts Outdated
Comment thread apps/app/src/modules/governance/pages/daoMembersPage/daoMembersPage.tsx Outdated
SPP evaluates a body through the stage plugin's interface type while the
totalSupply enrichment keyed off the sub-proposal's own interface type, so a
sub-proposal with inconsistent backend data reached the lock-to-vote status
utils without the enrichment and crashed the proposals page. Enrich by stage
body address as well and make the supply lookup tolerant to missing data.

Fixes APP-NEXT-2ES
…resses

The create proposal/process pages destructured the first useDaoPlugins result
unconditionally, so a direct load with an unknown or uninstalled plugin
address (or a not-yet-loaded DAO) crashed the page both server- and
client-side. The pages now render the standard not-found error state and the
permission guard skips its check until the plugin is resolved.

Fixes APP-NEXT-2EX
Fixes APP-NEXT-2EP
Unknown or malformed DAO addresses and proposal slugs (HEAD/GET bot traffic,
stale links) failed the server render and were reported to Sentry as errors.
URL-addressed lookups now map backend client errors to notFound(), the
metadata utils suppress the same class, and onRequestError skips expected
not-found errors for render paths without their own handling. The backend
error class also carries its name so Sentry titles are no longer a bare
"Error: ...".

Fixes APP-NEXT-248
Fixes APP-NEXT-2CF
Fixes APP-NEXT-2CE
Fixes APP-NEXT-2D9
Fixes APP-NEXT-24C
Fixes APP-NEXT-24D
formatterUtils.formatDate renders in the viewer's timezone (and RELATIVE
recomputes against "now"), while the server renders in UTC, so the members,
proposals, proposal-details and dashboard pages hydrated different text than
the server sent whenever a timestamp crossed a UTC boundary for the viewer's
zone. Gate those values behind useIsMounted, following the existing pattern
in daoProcessDetailsPageClient.

Fixes APP-NEXT-267
Fixes APP-NEXT-155
Fixes APP-NEXT-1YB
Fixes APP-NEXT-22
…ts) as expected

Adds an environmentNoisePatterns list to the beforeSend taxonomy for errors
injected by the user's environment rather than our code: WKWebView scripts
serializing cyclic structures, wallet extensions fighting over
window.ethereum, extensions mutating the DOM behind React, private-mode
storage, deploy skew and aborted streaming responses. Routed like expected
user behaviour — kept searchable, tagged expected, demoted to info — plus the
AppKit disconnect failure as expected wallet behaviour.

Fixes APP-NEXT-2B5
Fixes APP-NEXT-2D1
Fixes APP-NEXT-272
Fixes APP-NEXT-29W
Fixes APP-NEXT-2ED
Fixes APP-NEXT-2EZ
The linked-accounts-off filter compared plugin.daoAddress with the DAO record
address by strict string equality, so a checksum/lowercase mismatch between
the two backend fields silently dropped the plugin client-side while the
server-side daoUtils.getDaoPlugins kept it — crashing pages that dereference
the first plugin (e.g. gauge voter).

Fixes APP-NEXT-2B9

@thekidnamedkd thekidnamedkd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🩺

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants