Skip to content

fix(router): prevent stale onmatch rejections from redirecting - #3081

Open
sergioperezcheco wants to merge 1 commit into
MithrilJS:mainfrom
sergioperezcheco:fix/stale-onmatch-rejection
Open

sergioperezcheco wants to merge 1 commit into
MithrilJS:mainfrom
sergioperezcheco:fix/stale-onmatch-rejection

Conversation

@sergioperezcheco

Copy link
Copy Markdown

Description

Guard a rejected onmatch with the same resolver identity check already used for successful resolutions. A stale rejection is still logged, but cannot redirect a newer navigation to the fallback route. Rejections belonging to the current resolver retain their existing fallback behavior.

Motivation and Context

Start an asynchronous /slow route, navigate to /next, then reject the original promise. Currently the rejection calls route.set(fallbackRoute) even though /next has already resolved. It can also cancel a pending newer resolver or a route.set whose matching callback has not run yet.

This extends the existing latest-navigation-wins behavior discussed in #1461 and implemented for successful resolutions. The check uses resolver identity rather than the pathname, so reloading the same route is handled correctly. Error visibility from #2531 is preserved. This does not change fallback-route rejection behavior or attempt to redesign router lifecycle cancellation.

How Has This Been Tested?

On macOS, Node.js 22.22.3 and headless Chromium 151.0.7922.34:

  • Added five regression tests covering resolved and pending newer routes, immediate navigation, same-path navigation, and current-resolver fallback. With the original production code, 11 of their 18 assertions fail; all 18 pass with the fix.
  • Ran the complete npm test command against both versions: the original fails only the 11 new regression assertions; the fixed version passes all 1,132,071 assertions.
  • Built both versions with npm run build. Exercised the resulting full and minified bundles through the public m.route API in Chromium, checking rendered content, URL, resolved route, and retained error logging. The stale-rejection reproduction fails before the fix and passes after it. Additional browser controls cover pending navigation, immediate navigation, current fallback, and stale success.
  • Ran uncached ESLint across the repository and git diff --check successfully.

One earlier full-suite run exceeded an existing 200 ms timeout in a different router test; unchanged sequential reruns, including the final independent verification, passed. Other Node versions, operating systems, Firefox and WebKit were not tested locally.

AI assistance was used to develop this change and its tests; the patch and regression behavior were independently reviewed and exercised by a second automated pass.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My change requires a documentation update, and I've opened a pull request to update it already:
  • I have read https://mithril.js.org/contributing.html.

Preserve the latest navigation when an obsolete resolver rejects, while keeping its error visible.

Assisted-by: Hermes Agent
Signed-off-by: sergioperezcheco <checo520@outlook.com>
@sergioperezcheco
sergioperezcheco requested a review from a team as a code owner October 16, 2026 07:26

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.

1 participant