Skip to content

[Bug]: a host never retries a remote whose first server-side load failed #1424

Closed

Description

@Nsttt

Describe the bug

On the server, a __loadRemote__ wrapper is evaluated once and makes a single load attempt, exported as __mf_remote_pending (getEagerRemotePendingExport). If that attempt fails, every later import of the remote gets the same rejected promise for the life of the process. This happens, for example, when the host serves its first request while a remote is still deploying. The host never server-renders that remote again, even after the remote is back; only a restart helps.

In development the failure is cached a second time. Server wrappers export then (getServerThenExport), so Vite's module runner adopts the first load's rejection into the wrapper's cached evaluation promise, and every later import() of the wrapper rejects with it.

Version

@module-federation/vite 1.23.2 and main (9fd4193), Vite 8.3.2, Node 24 and 26.

Reproduction

  1. Start a host that imports a remote on the server (here, from a TanStack Start route loader) while the remote is stopped.
  2. Request the page. The remote fails to load and the host renders its fallback, as expected.
  3. Start the remote and request the page again. The host still renders the fallback, with the original error, on every request.

The scenario "SSR hosts that start during an outage render the remotes once they return" in module-federation/tanstack#1 automates this against vite dev and vite preview hosts.

Relevant log output

Repeated on every request after the remote is back:

Error in renderToReadableStream: Error: [ Federation Runtime ]: Failed to load Node.js entry for remote "__mfe_internal__tanstack_vite_host__mf_owner__228093996138680__tanstack_vite_remote" from "http://127.0.0.1:3001/remoteEntry.js". fetch failed

Proposed fix

Treat a failed attempt as retryable instead of final:

  • Once __mf_remote_pending rejects, replace it (and __mfRemotePending) with a thenable that starts a new __mfStartRemoteLoad() when the next importer awaits it. This needs the export to be let instead of const.
  • In development, let the then export resolve after a failed load, with live getters for default and __moduleExports and a __mf_remote_pending that forwards to the current attempt. The runner then caches a value that can still recover.

We patch the generated wrappers this way in @module-federation/tanstack (vite-compat.ts). It builds on #1421, which keeps an unawaited failed load from crashing the process.

Browser wrappers also make a single attempt, but a page reload clears that.

I can open a PR with this change.

Activity

  1. added
    bugSomething isn't working
    on Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions