Skip to content

fix(error-tracking): excuse the Gecko truncated-response fetch failure - #104120

Draft
posthog[bot] wants to merge 2 commits into
masterfrom
posthog-self-driving/fixerror-tracking-stop-filing-firefox-1aa53b
Draft

posthog[bot] wants to merge 2 commits into
masterfrom
posthog-self-driving/fixerror-tracking-stop-filing-firefox-1aa53b

Conversation

@posthog

@posthog posthog Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Problem

  • A Firefox user whose connection drops mid-response opens an error tracking issue. Nothing of ours failed and the app already recovers, so the issue is pure noise.
  • shouldReportApiFailure excuses a transport failure by matching the engine's wording against BROWSER_FETCH_FAILURE_MESSAGES. Gecko has two wordings, and only one was on the list.
  • The missing one is global to every kea loader, so any surface can file. The replay player retries a failed source three times and files once per attempt.

Changes

  • Firefox truncated responses stop reaching posthog.captureException. They keep toasting wherever they did, and client_request_failure still records the rate.
  • The mechanism is one added string in BROWSER_FETCH_FAILURE_MESSAGES:
 export const BROWSER_FETCH_FAILURE_MESSAGES: readonly string[] = [
     'Failed to fetch',
     'Load failed',
     'NetworkError when attempting to fetch resource',
+    'Content-Length header of network response exceeds response Body',
 ]
Engine Connection dropped Response arrived short
Chromium Failed to fetch —
WebKit Load failed —
Gecko NetworkError when attempting to fetch resource. Content-Length header of network response exceeds response Body.
  • The trailing period is left off, as with the existing Gecko entry — the match is includes.
  • MODULE_LOAD_FAILURE_MESSAGES still runs first, so a stale chunk after a deploy keeps reporting.

How did you test this code?

  • Added one case to the existing parameterized shouldReportApiFailure block in frontend/src/lib/api-error.test.ts. It catches the regression that no existing case did: a Gecko truncated-response TypeError classified as reportable.
  • Ran hogli test frontend/src/lib/api-error.test.ts locally; the suite passes.
  • No manual browser reproduction. The wording was confirmed against the exception events in the project rather than by inducing a truncated response in Firefox.

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Fully autonomous

Agent: Claude Code, Opus 5

  • No duplicate: gh pr list --state open --search over the relevant keywords found nothing.
  • The string was read off the project's own $exception events, not guessed from memory. An earlier guess at Gecko's wording would have been wrong.
  • The change deliberately stops at the allowlist. Widening isBrowserNetworkFailure to match on TypeError would have buried real crashes, which the existing comment already warns about.
  • Public artifact: the added string is a browser engine's own error text, already public. Nothing from the session is in the diff.
  • CodeRabbit CLI was not available in this environment, so the PR opens without a local review pass.
  • Skills invoked: writing-simplified-technical-english.

Created with PostHog Desktop from this inbox report.

Firefox words a response that arrives short of its own Content-Length header
differently from a dropped connection, and only the dropped-connection wording
was in BROWSER_FETCH_FAILURE_MESSAGES. The truncated one reached
posthog.captureException and opened a stack-grouped issue from every kea
loader that met it.

Generated-By: PostHog Desktop
Task-Id: 18197df8-7e15-4376-a759-95e5a7984e67
@trunk-io

trunk-io Bot commented Sep 21, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

A truncated response did reach the server, so the comment can no longer claim
every match never got there.

Generated-By: PostHog Desktop
Task-Id: 18197df8-7e15-4376-a759-95e5a7984e67
@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 2c2a35be-1b93-46e8-9c7b-9d4ec1f2d428

📥 Commits

Reviewing files that changed from the base of the PR and between 46ce43d and 7851cb9.

📒 Files selected for processing (2)
  • frontend/src/lib/api-error.test.ts
  • frontend/src/lib/api-error.ts

Included review availability: Your plan provides up to 12 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The browser failure classification now recognizes Gecko’s truncated-response TypeError message. Documentation covers incomplete or dropped responses. A test confirms that this failure is not reported.

Priority: ⬇️ Low

🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is complete and standalone. It explains the problem, user impact, implementation, preserved behavior, regression test, test command, lack of manual browser testing, documentation statu…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 1 function above the limit (max 14)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
shouldReportApiFailure frontend/src/lib/api-error.ts:194 14 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

⚠️ Bundle size — 🔺 +66 B (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 69.20 MiB · 🔺 +66 B (+0.0%)

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.56 MiB · 22 files no change ████████░░ 84.6% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.55 MiB · 628 files 🔺 +66 B (+0.0%) █████████░ 88.2% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.39 MiB · 2,772 files 🔺 +66 B (+0.0%) █████████░ 88.3% of 9.51 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/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 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
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts 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/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
854 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
301.9 KiB ../node_modules/.pnpm/posthog-js@1.434.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
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
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
104.6 KiB src/lib/api.ts
82.6 KiB src/products.tsx
68.5 KiB src/lib/lemon-ui/icons/icons.tsx
63.4 KiB src/lib/utils/eventUsageLogic.ts
38.8 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
28.5 KiB src/scenes/scenes.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
301.9 KiB ../node_modules/.pnpm/posthog-js@1.434.4_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
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
265.0 KiB src/taxonomy/core-filter-definitions-by-group.json
153.8 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
104.6 KiB src/lib/api.ts
98.4 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
82.6 KiB src/products.tsx

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.36 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.36 MiB · 19 files no change ████░░░░░░ 41.2% of 5.72 MiB
Deferred (lazy) 2.09 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
782.3 KiB dist/toolbar/toolbar-app-BE564NTX.css
649.5 KiB dist/toolbar/chunk-chunk-GZKLML6Z.js
483.6 KiB dist/toolbar/chunk-chunk-2PKLVDXN.js
138.1 KiB dist/toolbar/chunk-chunk-2JKMD6OO.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.1 KiB dist/toolbar/toolbar-app-ELGH35JS.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-NKOHS3J4.js
21.0 KiB dist/toolbar/chunk-chunk-TSQMXSSY.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🔺 +1.1 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1510.66 MiB · 🔺 +1.1 KiB (+0.0%)

@posthog

posthog Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

👋 Visual changes detected for this PR.

Review and approve in PostHog Visual Review

If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix.

@trunk-io

trunk-io Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Scenes-App/SidePanels SidePanelNotebooks smoke-test The test timed out while waiting for a loading indicator or spinner to disappear. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@posthog

posthog Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Visual review gate: the 4 diffs are calendar drift, not this PR

This PR changes one string in frontend/src/lib/api-error.ts and one test case. It renders no UI, so the 4 changed snapshots cannot come from it. Triaged rather than approved, per the bot's own advice above.

What changed. All 4 are the same story in two states and two themes:

products-data-modeling-model-health-summary--completed--{dark,light}
products-data-modeling-model-health-summary--running--{dark,light}

Comparing baseline against current, the only visible delta is one line of text:

Last successful refresh
Baseline (master, 2026-09-14) 2 days ago
This run (2026-09-21) 10 days ago

Root cause. ModelHealthSummary.stories.tsx pins an absolute date and the card renders it as a relative string:

lastSuccessfulSyncAt: '2026-09-12T10:00:00Z',

So the rendered text drifts by exactly the age of the baseline — 8 days here, matching the 8 days between the baseline commit and this run. Re-running CI will reproduce it identically. Dimensions are unchanged (896x130) and diff is ~0.38%, consistent with a few glyphs.

The sibling createdAt="2026-01-10T10:00:00Z" renders "8 months ago", which is why only the refresh line moves day to day.

Not specific to this branch. Three other open PRs on unrelated work show the identical signature (total 6018 / changed 4 / unchanged 6014): #104122, #104123, #104126.

Suggested fix, in its own PR — make the fixture relative so the rendered string is constant, e.g. derive lastSuccessfulSyncAt from dayjs().subtract(2, 'day'), or freeze the clock for the story. That belongs with the data modeling owners rather than in an error-tracking change.

Not approving or finalizing the baseline here: the diff is in another product's component and re-baselining it from this PR would hide the drift rather than fix it.

@carlos-marchal-ph carlos-marchal-ph removed their assignment Sep 22, 2026

This branch has not been deployed

No deployments
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.

1 participant