fix(livestream): stop capturing AbortErrors from cancelled SSE streams - #76426
fix(livestream): stop capturing AbortErrors from cancelled SSE streams#76426posthog[bot] wants to merge 1 commit into
Conversation
`api.stream()` (used for the sidebar's live notifications SSE connection, live events, and other streaming endpoints) had no guard around `fetchEventSource()` itself. Whenever the connection was torn down early — a visibility-pause disposable, an explicit stop, an unmount — the underlying fetch/stream reader can reject with a native `AbortError`, and with no catch in `stream()` that propagated as an unhandled rejection straight to exception capture instead of being treated as the clean cancellation it is. Also made the reverse proxy's suggested subdomain example (`t.mydomain.com`) click-to-copy, using the existing `CopyToClipboardInline` component, since it's plain unstyled text right next to a form asking the user to type that exact value in. branch: posthog-self-driving/fixapp-add-copy-affordances-where-users-a72361 Generated-By: PostHog Code Task-Id: 7989ab51-32b5-4b6d-953a-db925eac26fe
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report
|
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.25 MiB · 22 files | no change | ███░░░░░░░ 27.7% of 4.51 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.13 MiB · 3,035 files | 🔺 +56 B (+0.0%) | ████████░░ 83.8% of 9.71 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 285.6 KiB | ../node_modules/.pnpm/posthog-js@1.409.5/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.5 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 231.5 KiB | ../node_modules/.pnpm/posthog-js@1.409.5/node_modules/posthog-js/dist/module.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.3 KiB | src/lib/api.ts |
| 94.7 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Toolbar bundle — eager 2.19 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.19 MiB · 17 files | no change | ████░░░░░░ 38.3% of 5.72 MiB |
| Deferred (lazy) | 2.08 MiB · 33 files | no change | n/a — loads on demand |
Loader dist/toolbar.js |
1.1 KiB | no change | █░░░░░░░░░ 5.8% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 718.3 KiB | dist/toolbar/toolbar-app-FT4UJ3IP.css |
| 551.4 KiB | dist/toolbar/chunk-chunk-AGSGCCBT.js |
| 484.6 KiB | dist/toolbar/chunk-chunk-T44C2V5C.js |
| 133.6 KiB | dist/toolbar/chunk-chunk-KBLX73CM.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.0 KiB | dist/toolbar/toolbar-app-FKUW2FOM.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-3JVI3ZTF.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-HJ3ZJMTU.js |
| 12.2 KiB | dist/toolbar/chunk-chunk-PIK3PADE.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +3.9 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1381.31 MiB · 🔺 +3.9 KiB (+0.0%)
Problem
CodeSnippetblocks, event names in the Activity table, and Max's answer text are all plain, non-interactive text. Two independent sessions showed people rage-clicking or dead-clicking these exact spots, often while mid-setup (configuring an SDK, bouncing between proxy settings and the Activity page to verify events landed) — the worst time to hit friction.DOMException: AbortError: signal is aborted without reasoninto error tracking (28 on/settings/organization-proxy, 21 on/activity/explore).api.stream()inlib/api.ts— the helper behind the sidebar's live-notifications SSE connection (and other streaming endpoints). It mounts app-wide, which is why the error shows up on effectively every page, not just the two the report called out. Whenever that connection is torn down early (tab hidden, explicit stop, unmount), the underlying fetch/stream reader can reject with a nativeAbortError, andstream()had no catch aroundfetchEventSource()to treat that as the clean cancellation it is — so it reached exception capture as an unhandled rejection instead.Changes
lib/api.ts: wrapapi.stream()'sfetchEventSource()call in a try/catch that swallowsAbortError(matching theisAbortErrorconvention already used elsewhere in this file) and rethrows anything else.ManagedReverseProxy.tsx: wrap the suggested subdomain example (t.mydomain.com) in the existingCopyToClipboardInlinecomponent so it's click-to-copy, since it sits right next to a form asking the user to type that exact value.I scoped this PR to the two clearest, most defensible fixes rather than the full list of copy affordances the report raised (
CodeSnippetper-value copy, Activity table event-name click, a hover copy control on Max message bubbles) — those are real UX friction with existing workarounds (drag-select, whole-block copy) and each is its own small design decision better done as a follow-up than bundled here.How did you test this code?
lib/api.test.tscoveringapi.stream(): resolves cleanly when the underlying stream rejects withAbortError, and still propagates non-abort errors. Neither existing test exercised this path.pnpm --filter=@posthog/frontend typescript:checkandfix(lint + format) — clean on the changed files (pre-existing unrelated failures elsewhere in the repo, from a missing@posthog/quill-primitivespackage, are untouched by this change).CopyToClipboardInlinebeing an existing, already-used component for exactly this pattern (wrapping literal text children for click-to-copy).Automatic notifications
Docs update
N/A — no user-facing workflow or API changed.
🤖 Agent context
Autonomy: Fully autonomous
Investigated via the PostHog MCP error-tracking tools to find the actual issue behind the reported
AbortErrormessage (not just the two sessions cited in the report), which is what pointed atapi.stream()inlib/api.tsrather than thedataNodeLogic.ts/proxy-logic code paths the report's own analysis suggested. Ruled out thedataNodeLogic.tslazyLoaderscount-query catches as a red herring — those don't currently pass anAbortSignalso can't produce this specific native abort message. Descoped the CodeSnippet/Activity-table/Max-bubble copy affordances mentioned in the report to a follow-up, since verifying those needed either a live app session or a larger design call I didn't want to make unreviewed.Created with PostHog Desktop from this inbox report.