fix(api,relay,marketing,ui): clear four Sentry issue families

Merged
SA
3mo ago
+74-7

Fixes the four highest-signal unresolved Sentry issue families whose root causes were clear from stack traces + code.

1. Webhook events dropped on NUL bytes — api (Fixes API-10)

GitHub webhook payloads carry U+0000 inside code-diff strings; Postgres jsonb rejects them (NeonDbError: unsupported Unicode escape sequence), so the insert into ingest.webhook_events failed and the event was lost (335 events / 116 orgs over 30d). New stripNullChars deep-cleans payloads before insert on both the GitHub and Linear webhook routes. Functionally verified against a payload shaped like the failing event.

2. Relay tunnel lifecycle noise — relay (Fixes RELAY-1, RELAY-2, RELAY-3, RELAY-4)

"Tunnel disconnected" / "Request timed out" / "Replaced by new tunnel" / "Host not connected" are routine churn but were reported as unhandled exceptions — ~66k Sentry events in 30 days, burying real errors. They're now a typed TunnelLifecycleError dropped in beforeSend; callers still receive the rejections unchanged.

3. Shader crash on non-WebGL browsers — marketing (Fixes MARKETING-35)

@paper-design/shaders-react throws when WebGL is unavailable (bots, old devices — 4k events / 480 users). The decorative DitheredBackground now feature-detects WebGL (cached probe, post-hydration) and renders nothing without it.

4. Gradient unmount crash — ui/web (Fixes WEB-17)

MeshGradient's unmount defense swaps stripe-gradient's el to a detached dummy — but the lib's delayed init reads el.parentElement.classList, and the dummy had no parent, converting the defense into the crash (694 events / 132 users on /agents). The decoy now has both a parent and a child.

Not in this PR (triaged, deeper work)

  • API-15/API-1M: crash inside better-auth 1.6.13's endpoint wrapper on /.well-known/oauth-authorization-server — needs an upstream check/bump.
  • RELAY-5: Bun's ws shim rejects node-ws upgrades ("upgrade requires a Request object") — adapter-level change (hono/bun websocket helper).
  • API-18/19/1B/1F/…: one family of transient Neon disconnects — candidate for a shared retry wrapper.
  • Browser-extension noise across web/docs/marketing (MetaMask/keplr/tronlink/onMessage/sseError): to be archived in Sentry, not fixed in code.

Verification

Typecheck clean in api, relay, marketing, ui; Biome lint exits 0; stripNullChars verified with a NUL-carrying payload (5/5 assertions).

https://claude.ai/code/session_01BQ71xVEeJRhAqiU4Dfc5Fs


Open in Stage

Summary by cubic

Fixes four high-signal Sentry issue families to stop dropped webhooks, silence expected relay churn, and prevent two frontend crashes. Improves stability across api, relay, marketing, and ui.

  • Bug Fixes
    • API-10: Strip U+0000 from GitHub/Linear webhook payloads with stripNullChars before writing to Postgres jsonb to prevent failed inserts.
    • RELAY-1/2/3/4: Classify routine tunnel churn as TunnelLifecycleError and drop it in Sentry beforeSend; callers still get rejections.
    • MARKETING-35: Gate DitheredBackground behind a cached WebGL feature check; render nothing when unsupported to avoid @paper-design/shaders-react crashes.
    • WEB-17: Update MeshGradient unmount decoy to have a parent and child to satisfy stripe-gradient delayed reads.

Summary by CodeRabbit

  • Bug Fixes

    • Improved webhook reliability by safely handling unexpected null characters in incoming payloads.
    • Prevented unsupported browsers or devices from displaying the marketing page’s WebGL background incorrectly.
    • Improved handling of expected connection lifecycle failures, reducing unnecessary error reporting.
    • Fixed cleanup behavior for gradient visuals to prevent potential rendering issues.
  • Reliability

    • Preserved webhook processing behavior while making stored event data safer and more consistent.