Skip to content

fix(frontend): stop swallowing Vite preload errors into router crashes - #2887

Draft
posthog-eu[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixfrontend-stop-swallowing-vite-319f87
Draft

fix(frontend): stop swallowing Vite preload errors into router crashes#2887
posthog-eu[bot] wants to merge 1 commit into
mainfrom
posthog-self-driving/fixfrontend-stop-swallowing-vite-319f87

Conversation

@posthog-eu

@posthog-eu posthog-eu Bot commented Aug 6, 2026

Copy link
Copy Markdown

Summary

  • Who's hurt: users mid-session during a deploy hit a dead page instead of the auto-reload built for exactly this case. Every deploy that lands while a stale index.html is open can trigger it — any lazy route, not just the device page.
  • Root cause: the vite:preloadError handler in src/main.ts called event.preventDefault(). Vite's preload helper only rethrows the import failure when !e.defaultPrevented, so preventing the default makes __vitePreload resolve with undefined. The lazy route then resolves to a falsy component and vue-router throws Couldn't resolve component "default" at ... — a hard crash.
  • Extra sting: that router error text matches none of STALE_ASSET_ERROR_PATTERNS, so the PostHog suppression this code was written to provide never applied to the error it created. The real Failed to fetch dynamically imported module cause was swallowed; only the downstream router error escaped.

Changes

  • Drop event.preventDefault() (and the now-pointless stopImmediatePropagation()) from the vite:preloadError handler so Vite rethrows. The rejection surfaces as Failed to fetch dynamically imported module, which the existing patterns in src/services/staleAssetErrors.ts already match — restoring both the auto-reload and the PostHog suppression that were intended.
  • Add a router.onError fallback that treats Couldn't resolve component as a chunk error too, so a navigation that races the async window.location.reload() still recovers instead of leaving a blank route.
  • New isComponentResolutionErrorMessage helper + unit coverage.

Note

Adding the Couldn't resolve component pattern to the PostHog suppression list on its own would only hide the symptom — the root-cause fix is removing preventDefault(). The router.onError handler catches the error before it propagates, so it no longer reaches PostHog's exception autocapture.

Test plan

  • vitest run tests/stale-asset-errors.unit.test.ts — 6 passing (includes new component-resolution matcher cases).
  • Manual: deploy invalidating chunk URLs while an old index.html is open → navigating to a lazy route now auto-reloads to the latest version instead of crashing on Couldn't resolve component.

Screenshots

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • My change has adequate E2E test coverage.
  • I have tested my code manually, and I have provided steps how to reproduce my tests.

Created with PostHog Desktop from this inbox report.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Review in cubic

The vite:preloadError handler called event.preventDefault(), which makes
Vite's preload helper resolve with undefined instead of rethrowing. A lazy
route then resolves to a falsy component and vue-router throws "Couldn't
resolve component", a hard crash that also escapes the PostHog stale-asset
suppression.

Drop preventDefault() so the rejection surfaces as "Failed to fetch
dynamically imported module" (already matched by STALE_ASSET_ERROR_PATTERNS),
restoring both the auto-reload and the PostHog suppression. Add a
router.onError fallback that treats "Couldn't resolve component" as a chunk
error too, so a navigation that races the reload still recovers.

Generated-By: PostHog Code
Task-Id: 8387f1f6-97b6-447f-8ff4-d425a275e501
@codspeed-hq

codspeed-hq Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing posthog-self-driving/fixfrontend-stop-swallowing-vite-319f87 (3e2f827) with main (60a641e)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@sonarqubecloud

sonarqubecloud Bot commented Aug 6, 2026

Copy link
Copy Markdown

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.

0 participants