Skip to content

Core config editor route can get stuck without console error because vite:preloadError is always preventDefault'ed #500

@Rerowros

Description

@Rerowros

Describe the bug
After upgrading to v4.0.2, the Core Config editor route can get stuck.

When opening /dashboard/#/nodes/cores/{id}, the URL changes, but the editor UI does not render. In my case, Chrome DevTools Console may show no useful runtime error. Chrome DevTools Issues only reports unrelated form/accessibility warnings, such as missing id/name/autocomplete or label mismatch, but those warnings do not explain the route not rendering.

The likely problem is in chunk-recovery.ts: vite:preloadError is always suppressed with event.preventDefault(), even when recoverFromChunkLoadError(...) does not actually recover/reload.

https://github.com/PasarGuard/panel/blob/v4.0.2/dashboard/src/utils/chunk-recovery.ts#L92-L99

Vite docs say that calling event.preventDefault() prevents the preload error from being thrown:

https://vite.dev/guide/build#load-error-handling

The Core Config editor route is lazy-loaded here:

https://github.com/PasarGuard/panel/blob/v4.0.2/dashboard/src/app/router.tsx#L7-L12

And mounted here:

https://github.com/PasarGuard/panel/blob/v4.0.2/dashboard/src/app/router.tsx#L130-L151

lazyWithChunkRecovery returns await importer() directly and does not validate that the resolved module contains a valid default export:

https://github.com/PasarGuard/panel/blob/v4.0.2/dashboard/src/utils/chunk-recovery.ts#L108-L121

React lazy() expects the promise to resolve to an object with a valid .default component:

https://react.dev/reference/react/lazy

To Reproduce
Steps to reproduce the behavior:

  1. Upgrade panel to v4.0.2.
  2. Open the dashboard in Chrome.
  3. Go to Nodes.
  4. Open Core Configs.
  5. Click any existing core config.
  6. URL changes to /dashboard/#/nodes/cores/{id}.
  7. The Core Config editor does not render / page stays stuck.
  8. Console may be empty because the preload error is suppressed.

Expected behavior
The Core Config editor should render normally after opening /dashboard/#/nodes/cores/{id}.

If a stale or broken chunk is detected, the app should either reload/recover or surface the real error in the console. It should not silently suppress the preload error and leave the route stuck.

Machine details (please complete the following information):

  • Server OS: Ubuntu 24.04
  • Deployment: Docker Compose
  • Panel version: v4.0.2
  • Browser: Chrome on Windows 11

Additional context
Suggested fix: only call event.preventDefault() if recovery actually starts:

window.addEventListener('vite:preloadError', (event) => {
  const preloadError =
    'payload' in event
      ? (event as Event & { payload: unknown }).payload
      : (event as CustomEvent<unknown>).detail

  if (recoverFromChunkLoadError(preloadError ?? event)) {
    event.preventDefault()
  }
})

Also validate the lazy-loaded module shape

  importer: () => Promise<{ default: T }>,
) {
  return lazy(async () => {
    try {
      const module = await importer()

      if (!module || typeof module !== 'object' || !('default' in module)) {
        throw new Error('Lazy chunk resolved without a default export')
      }

      return module
    } catch (error) {
      if (recoverFromChunkLoadError(error)) {
        return new Promise<{ default: T }>(() => undefined)
      }

      throw error
    }
  })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions