Skip to content

fix(runtime): enable SSR remote-entry retry and URL failover - #4968

Open
dmchoi77 wants to merge 3 commits into
module-federation:mainfrom
dmchoi77:fix/ssr-remote-entry-retry
Open

fix(runtime): enable SSR remote-entry retry and URL failover#4968
dmchoi77 wants to merge 3 commits into
module-federation:mainfrom
dmchoi77:fix/ssr-remote-entry-retry

Conversation

@dmchoi77

@dmchoi77 dmchoi77 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes Node.js/SSR remote-entry transport failures that currently bypass the loadEntryError lifecycle.

loadEntryNode now follows the same retryable RUNTIME_008 path as the browser loader, and the Node loader receives getEntryUrl so retry-plugin URL rewrites (domain failover and cache-busting queries) are applied during SSR as well.

Remote-entry execution failures remain non-retryable. The Node SDK now marks transport failures as ScriptNetworkError and execution failures as ScriptExecutionError; hook/configuration failures retain their original errors.

The change reuses the existing runtime error lifecycle and browser error handling pattern. No new public utility or retry API is introduced.

Regression coverage verifies:

  • Node transport failures dispatch loadEntryError and can recover with a rewritten URL.
  • Unrecovered transport failures include RUNTIME_008.
  • Remote-entry execution failures do not invoke retry handling.
  • createScript hook failures are not misclassified as network failures.
  • Node script error classification is preserved by the SDK.

Validation

All commands below were run with Node.js 24.19.0 and pnpm 10.28.0:

  • pnpm --filter @module-federation/runtime-core exec rstest run tests/node-load.spec.ts --testNamePattern='Node.js entry loading'
  • pnpm --filter @module-federation/sdk test -- --runInBand node-builtin-esm.spec.ts
  • pnpm --filter @module-federation/runtime-core test
  • pnpm --filter @module-federation/sdk test
  • pnpm --filter @module-federation/runtime-core run build
  • pnpm --filter @module-federation/sdk run build

Related Issue

Closes #4963

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have updated the documentation.

@changeset-bot

changeset-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 108c924

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 47 packages
Name Type
@module-federation/runtime-core Patch
@module-federation/sdk Patch
@module-federation/retry-plugin Patch
@module-federation/nextjs-mf Patch
@module-federation/runtime Patch
@module-federation/bridge-react Patch
@module-federation/devtools Patch
@module-federation/cli Patch
@module-federation/dts-plugin Patch
@module-federation/enhanced Patch
@module-federation/esbuild Patch
@module-federation/managers Patch
@module-federation/manifest Patch
@module-federation/metro Patch
@module-federation/modern-js-v3 Patch
@module-federation/modern-js Patch
@module-federation/node Patch
@module-federation/observability-plugin Patch
@module-federation/rsbuild-plugin Patch
@module-federation/rspack Patch
@module-federation/rspress-plugin Patch
@module-federation/storybook-addon Patch
@module-federation/utilities Patch
@module-federation/webpack-bundler-runtime Patch
@module-federation/bridge-react-webpack-plugin Patch
@module-federation/bridge-vue3 Patch
@module-federation/playground Patch
@module-federation/runtime-tools Patch
website-new Patch
shared-tree-shaking-no-server-host Patch
shared-tree-shaking-no-server-provider Patch
@module-federation/metro-plugin-rnc-cli Patch
@module-federation/metro-plugin-rnef Patch
@module-federation/metro-plugin-rock Patch
shared-tree-shaking-with-server-host Patch
shared-tree-shaking-with-server-provider Patch
node-dynamic-remote-new-version Patch
node-dynamic-remote Patch
remote5 Patch
remote6 Patch
@module-federation/inject-external-runtime-core-plugin Patch
@module-federation/third-party-dts-extractor Patch
@module-federation/bridge-shared Patch
@module-federation/error-codes Patch
create-module-federation Patch
@module-federation/treeshake-server Patch
@module-federation/treeshake-frontend Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13639e3681

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/sdk/src/node.ts
@2heal1

2heal1 commented Aug 18, 2026

Copy link
Copy Markdown
Member

Thanks for adding Node.js SSR remote-entry retry support. The overall direction looks good, but I found a few retry edge cases that should be addressed before merging.

  1. ESM modules that fail while linking remain in esmModuleCache.

For example:

remoteEntry -> chunk-a -> chunk-b

If the first fetch of chunk-b fails, chunk-a remains cached as an errored SourceTextModule. Retrying the entry with ?retryCount=1 still resolves chunk-a to the same URL, so the retry
reads the poisoned cache entry and fails with:

ERR_VM_MODULE_LINK_FAILURE: request for './chunk-a.mjs' resolved to an errored module

The error is then reclassified as ScriptExecutionError, so the retry cannot recover even after chunk-b becomes available. Could we evict modules from esmModuleCache when linking or
evaluation fails, and add a test covering a transient failure in a transitive ESM dependency?

  1. Execution errors are only treated as non-retryable on the initial attempt.

Once loadEntryError has started scriptRetry, a retry attempt that throws ScriptExecutionError is caught by scriptRetry like any other error, and the remaining attempts still run. This
can execute a partially failing remote multiple times and contradicts the changeset’s “execution errors non-retryable” behavior.

Could scriptRetry immediately rethrow ScriptExecutionError and preserve the original error? A test where the initial load has a network failure and the first retry has an execution failure
would cover this case.

  1. Invalid URLs are currently classified as network errors.

A failure from new URL(url) is a configuration/URL validation error, not a transport failure. Classifying it as ScriptNetworkError sends it through RUNTIME_008 and retry-plugin, even
though retrying cannot repair the URL and may replace the useful ERR_INVALID_URL with a generic retry-abandoned error.

I verified that the existing SDK/runtime-core tests and builds pass. The additional ESM cache and execution-error-during-retry cases above both reproduce consistently.

@dmchoi77

Copy link
Copy Markdown
Contributor Author

@2heal1 Thanks for the detailed review. I addressed all three retry edge cases:

  1. Failed ESM modules are now evicted from esmModuleCache when linking or evaluation fails, including transitive dependencies. Added a regression test for a transient transitive chunk failure.

  2. scriptRetry now immediately rethrows ScriptExecutionError during retry attempts and preserves the original error. Added coverage for an initial network failure followed by an execution failure.

  3. Invalid URLs now propagate the original URL validation error instead of being classified as ScriptNetworkError/RUNTIME_008 or entering the retry flow. Added SDK and runtime-core coverage.

108c924

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node/SSR remote-entry load failures do not trigger loadEntryError

2 participants