Skip to content

fix(script-manager): allow retry after resolveScript failure - #1507

Open
linhh-phv wants to merge 1 commit into
callstack:mainfrom
linhh-phv:fix/script-manager-retry-after-resolve-failure
Open

linhh-phv wants to merge 1 commit into
callstack:mainfrom
linhh-phv:fix/script-manager-retry-after-resolve-failure

Conversation

@linhh-phv

Copy link
Copy Markdown

Summary

Fixes #1506.

loadScript and prefetchScript awaited resolveScript outside the try / finally that removes the entry from scriptsPromises. When a resolver threw (for example, the device was offline while resolving the script URL), the rejected promise stayed cached. Every later call for the same script then returned that error without calling the resolvers again, until the app was restarted.

This PR catches errors from resolveScript, removes the cached promise, and rethrows the same error:

let script: Script;
try {
  script = await this.resolveScript(/* ... */);
} catch (error) {
  // resolving failed - remove the rejected promise so that
  // subsequent calls can retry instead of reusing this failure
  delete this.scriptsPromises[uniqueId];
  throw error;
}

What does not change:

  • Callers get the same error object, and handleError / the error event still fire once, inside resolveScript.
  • The existing try / catch / finally around loading is untouched. I didn't move resolveScript into it, because its catch reads script.toObject() and calls handleError again, which would report a resolve error twice.

A changeset (patch) is included.

Test plan

  • Added should retry loadScript after resolver failure and should retry prefetchScript after resolver failure: the resolver rejects once, then resolves. The second call must succeed and call the resolver again.
    • Without the fix: both new tests fail (the second call rejects with the first error, and the resolver is called once).
    • With the fix: ScriptManager tests 50/50 pass.
  • pnpm typecheck (packages/repack), biome check on the changed files, and the full @callstack/repack jest suite (41 suites, 361 tests) pass.
  • We have run the same change as a patch-package patch on top of 5.2.5 in a production app (iOS + Android, Module Federation v1). Opening a remote while offline, then going online and retrying, now loads the remote without restarting the app.

`loadScript` and `prefetchScript` awaited `resolveScript` outside the
try/finally that removes the entry from `scriptsPromises`. When a
resolver threw, the rejected promise stayed cached and every later call
for the same script returned the same error without resolving again.

Remove the cached promise when resolving fails and rethrow, so the next
call can retry.
@changeset-bot

changeset-bot Bot commented Oct 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3cf56d7

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

This PR includes changesets to release 6 packages
Name Type
@callstack/repack Patch
@callstack/repack-plugin-expo-modules Patch
@callstack/repack-plugin-nativewind Patch
@callstack/repack-plugin-reanimated Patch
@callstack/repack-dev-server Patch
@callstack/repack-init 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

@vercel

vercel Bot commented Oct 20, 2026

Copy link
Copy Markdown

@linhh-phv is attempting to deploy a commit to the Callstack Team on Vercel.

A member of the Team first needs to authorize it.

This branch has not been deployed

No deployments
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.

ScriptManager caches the rejected promise when a resolver throws, so loadScript/prefetchScript never retry

1 participant