Skip to content

fix(frontend): suppress stale asset PostHog errors#1883

Merged
riderx merged 2 commits intomainfrom
codex/filter-posthog-stale-asset-errors
Apr 1, 2026
Merged

fix(frontend): suppress stale asset PostHog errors#1883
riderx merged 2 commits intomainfrom
codex/filter-posthog-stale-asset-errors

Conversation

@riderx
Copy link
Copy Markdown
Member

@riderx riderx commented Apr 1, 2026

Summary (AI generated)

  • expand the console stale-asset detector to catch the chunk, module-script, MIME-type, and CSS preload failures currently dominating PostHog errors
  • handle Vite preload failures explicitly and stop propagation before PostHog autocapture records them
  • add a narrow PostHog before_send filter so only this recoverable stale-asset class is dropped
  • add unit coverage for stale-asset classification and PostHog suppression behavior

Motivation (AI generated)

The Capgo PostHog project currently has active frontend error noise from stale asset deployments on console.capgo.app, including dynamic import failures, CSS preload failures, and invalid JavaScript MIME type errors. These are recoverable deployment-version mismatches rather than actionable application defects, so the app should recover automatically and avoid polluting PostHog with expected stale-asset exceptions.

Business Impact (AI generated)

This reduces false-positive frontend error volume in PostHog, making real regressions easier to spot and triage. It also improves the user experience during deploy rollouts by reloading once to recover from stale assets instead of leaving users stranded on a broken chunk.

Test Plan (AI generated)

  • bun lint
  • bunx vitest run tests/stale-asset-errors.unit.test.ts
  • bun typecheck
  • bun run build

Generated with AI

Summary by CodeRabbit

  • Bug Fixes

    • Improved detection and handling of stale asset/preload errors with unified normalization and safer reload handling.
    • Added a 30s session-based reload cooldown and toast gating to avoid repeated automatic reloads.
    • Routes preload failures through the same recovery flow for more reliable recovery.
    • Suppresses duplicate exception reports for known stale-asset errors.
  • Tests

    • Added unit tests covering stale-asset detection, message normalization, and analytics-suppression logic.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89450a2a-cf0a-4ec7-9471-55d49e0e7bba

📥 Commits

Reviewing files that changed from the base of the PR and between 2616145 and 058ad70.

📒 Files selected for processing (3)
  • src/main.ts
  • src/services/staleAssetErrors.ts
  • tests/stale-asset-errors.unit.test.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/stale-asset-errors.unit.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main.ts
  • src/services/staleAssetErrors.ts

📝 Walkthrough

Walkthrough

Reworked stale-chunk detection to use a new helper module (message normalization + regex matching) for both window.error and window.unhandledrejection. Added session-based reload cooldown and toast gating, stronger event propagation control before reloads, a vite:preloadError listener, and PostHog suppression via a before_send hook.

Changes

Cohort / File(s) Summary
Stale Asset Detection Service
src/services/staleAssetErrors.ts
New module providing isStaleAssetErrorMessage(message), getErrorMessage(value), and shouldSuppressPostHogExceptionEvent(event) to normalize messages and detect stale-asset/preload errors via regex.
Main Error Handling
src/main.ts
Replaced ad-hoc substring checks with getErrorMessage() + isStaleAssetErrorMessage(). Added vite:preloadError listener. Call event.preventDefault() and event.stopImmediatePropagation() before reload flows. Switched from localStorage flag to session-scoped timestamp (CHUNK_RELOAD_TIMESTAMP_KEY) and session toast gating (CHUNK_RELOAD_TOAST_KEY) enforcing a 30s cooldown.
PostHog Integration
src/services/posthog.ts
posthog.init() gets a before_send hook that calls shouldSuppressPostHogExceptionEvent() to drop stale-asset $exception events.
Unit Tests
tests/stale-asset-errors.unit.test.ts
New Vitest suite validating pattern matching, message normalization, and PostHog exception filtering across payload shapes ($exception_list, $exception_values, etc.).

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client/Browser
    participant Main as src/main.ts
    participant Detection as src/services/staleAssetErrors.ts
    participant PostHog as PostHog Service

    Client->>Main: runtime error / unhandledrejection / preload error
    Main->>Detection: getErrorMessage(error)
    Detection-->>Main: normalized message
    Main->>Detection: isStaleAssetErrorMessage(message)
    Detection-->>Main: true (stale asset)
    Main->>Main: event.preventDefault() + stopImmediatePropagation()
    alt within 30s cooldown (session)
        Main-->>Client: suppress reload
    else outside cooldown
        Main->>Main: set CHUNK_RELOAD_TIMESTAMP_KEY
        Main->>Client: trigger page reload
        Main->>Main: set CHUNK_RELOAD_TOAST_KEY (show post-reload toast once)
    end

    Note over PostHog: Asynchronous analytics filtering
    Client-->>PostHog: $exception event
    PostHog->>Detection: shouldSuppressPostHogExceptionEvent(event)
    Detection-->>PostHog: true (suppress)
    PostHog-->>PostHog: drop event (before_send returns false)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I sniffed a stale chunk in the night,
I normalized messages by soft moonlight,
Thirty seconds hush, then a gentle reload,
PostHog kept quiet on that bumpy road,
Hooray — logs tidy, and hoppity bright!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description includes a comprehensive summary and motivation, but the provided test plan section lacks detailed step-by-step testing instructions and omits screenshots section, which are requested in the template. Add detailed step-by-step reproduction steps for manual testing, and clarify whether screenshots/videos are applicable for this frontend change.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main objective: suppressing stale asset errors from PostHog reporting, which aligns with the primary changes across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/filter-posthog-stale-asset-errors

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

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq bot commented Apr 1, 2026

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing codex/filter-posthog-stale-asset-errors (058ad70) with main (fd65cb6)

Open in CodSpeed

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/stale-asset-errors.unit.test.ts (1)

6-47: Use it.concurrent() for these test cases.

All four test cases call pure functions with no shared mutable state, making them safe candidates for parallel execution. This aligns with the repo's test parallelism pattern.

♻️ Suggested change
-  it('matches the stale asset errors currently seen in PostHog', () => {
+  it.concurrent('matches the stale asset errors currently seen in PostHog', () => {

-  it('does not match unrelated runtime errors', () => {
+  it.concurrent('does not match unrelated runtime errors', () => {

-  it('extracts useful messages from arbitrary rejection values', () => {
+  it.concurrent('extracts useful messages from arbitrary rejection values', () => {

-  it('suppresses only stale asset exception events in PostHog', () => {
+  it.concurrent('suppresses only stale asset exception events in PostHog', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/stale-asset-errors.unit.test.ts` around lines 6 - 47, Replace the four
sequential tests with concurrent tests by changing their declarations from
it(...) to it.concurrent(...); specifically update the tests that call
isStaleAssetErrorMessage, getErrorMessage, and
shouldSuppressPostHogExceptionEvent so the specs "matches the stale asset
errors...", "does not match unrelated runtime errors", "extracts useful messages
from arbitrary rejection values", and "suppresses only stale asset exception
events in PostHog" use it.concurrent to run in parallel (these tests call pure
functions with no shared mutable state).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main.ts`:
- Around line 175-179: The code clears the reload timestamp right after showing
the toast which disables the 30s cooldown; instead, stop clearing the timestamp
in this toast path and either (A) introduce a separate "toast shown" flag (e.g.,
setChunkReloadToastShown / getChunkReloadToastShown /
clearChunkReloadToastShown) to track whether the UI toast was already displayed,
or (B) only clear the reload timestamp after the cooldown window expires (e.g.,
let handleChunkError keep the timestamp for 30s and call
clearChunkReloadTimestamp once the cooldown elapses). Update the toast code to
use the new toast-flag API (or remove clearChunkReloadTimestamp here) and ensure
handleChunkError still reads getChunkReloadTimestamp to enforce the cooldown.
- Around line 88-96: The preload error handler currently suppresses all
'vite:preloadError' events and routes them to handleChunkError; change it to
first compute the message via getErrorMessage(preloadEvent.payload) ||
getErrorMessage(preloadEvent.detail) || 'Vite preload error', then call
isStaleAssetErrorMessage(message) and only if that returns true call
event.preventDefault(), event.stopImmediatePropagation(), and
handleChunkError(message). This keeps non-stale preload errors from being
suppressed while still routing genuine stale-asset messages through
handleChunkError.

In `@src/services/staleAssetErrors.ts`:
- Around line 1-9: The regex in STALE_ASSET_ERROR_PATTERNS is too broad for the
MIME-type case; tighten it to only match the HTML-fallback scenario (e.g.
messages that mention "is not a valid JavaScript MIME type" together with
"text/html" or similar) or else require the asset path context before treating
it as a stale-deploy; update the pattern in STALE_ASSET_ERROR_PATTERNS and add a
unit test that verifies non-HTML mismatches (like application/json or
text/plain) do not trigger the stale-asset detection while HTML fallback does.

---

Nitpick comments:
In `@tests/stale-asset-errors.unit.test.ts`:
- Around line 6-47: Replace the four sequential tests with concurrent tests by
changing their declarations from it(...) to it.concurrent(...); specifically
update the tests that call isStaleAssetErrorMessage, getErrorMessage, and
shouldSuppressPostHogExceptionEvent so the specs "matches the stale asset
errors...", "does not match unrelated runtime errors", "extracts useful messages
from arbitrary rejection values", and "suppresses only stale asset exception
events in PostHog" use it.concurrent to run in parallel (these tests call pure
functions with no shared mutable state).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20b8682b-9af3-47e7-aefe-274b65e94912

📥 Commits

Reviewing files that changed from the base of the PR and between 947a6c9 and 2616145.

📒 Files selected for processing (4)
  • src/main.ts
  • src/services/posthog.ts
  • src/services/staleAssetErrors.ts
  • tests/stale-asset-errors.unit.test.ts

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 1, 2026

@riderx riderx merged commit 5fe33ce into main Apr 1, 2026
17 checks passed
@riderx riderx deleted the codex/filter-posthog-stale-asset-errors branch April 1, 2026 13:36
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