Skip to content

fix: abort superseded preloads - #17080

Open
gcamargosilva wants to merge 1 commit into
sveltejs:version-3from
gcamargosilva:fix/abort-superseded-preload
Open

fix: abort superseded preloads#17080
gcamargosilva wants to merge 1 commit into
sveltejs:version-3from
gcamargosilva:fix/abort-superseded-preload

Conversation

@gcamargosilva

@gcamargosilva gcamargosilva commented Sep 9, 2026

Copy link
Copy Markdown

Context

Hello guys,

I'm not sure if this is a specific edge case, but I have an Svelte app with many links where some preloads can take 1s+.

When hovering over multiple links, the previous preloads keep running even after they've been superseded. When the user clicks a link, this can make the navigation wait for those previous preloads to finish.

During the investigation, I noticed that preloads don't have an AbortController, so I couldn't find a way to cancel these requests.

Proposed fix

This PR aborts in-flight requests when a speculative preload is superseded by a newer one.

The signal is propagated through load_route to both the __data.json request and the fetch available to load functions.

Once a preload is consumed by a real navigation, it is no longer aborted, so user-initiated navigation remains unaffected.

I also fixed two related issues around rejected preload promises/unhandled rejections that became apparent while implementing this.

I'm not sure whether this is a broader problem or just an edge case from my application, so feel free to reject this PR if the behavior doesn't make sense for SvelteKit's preload model.


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

data-sveltekit-preload-data aborts a superseded preload was verified to fail on version-3 and pass with this change. The full test-basics Playwright suite passes (693 passed, 0 failed), as do oxfmt --check, eslint, and tsc on packages/kit (the pre-existing src/exports/vite/index.js TS2321 is unrelated and also present on version-3).

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

When a `data-sveltekit-preload-data` preload is superseded by a preload for
another link, its in-flight requests are now aborted instead of running to
completion. The `AbortSignal` is threaded through `load_route` into both the
`__data.json` request and the `fetch` passed to `load`.

Aborting only happens while the preload is still speculative — once its token
has been consumed by a real navigation, `discard_load_cache` leaves it alone so
the navigation the user asked for isn't cancelled.

`preloadData()` is unaffected: it passes no `AbortController`, so its requests
are never cancelled by a subsequent preload.

Two related fixes:

- a superseded preload rejects after `load_cache` has already been replaced, so
  the rejection handler now only discards the cache when it still owns it
- `discard_load_cache` attached no rejection handler to `load_cache.fork`, which
  turned every aborted preload into an unhandled rejection under
  `experimental.forkPreloads`
@pkg-svelte-dev

pkg-svelte-dev Bot commented Sep 9, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 56bf4fe:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/56bf4fefff27fb63918a0251d753dedc3454f51e

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/17080

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 56bf4fe

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

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit 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

@gcamargosilva
gcamargosilva marked this pull request as ready for review September 9, 2026 16:47
});
} else {
void _preload_data(intent);
void _preload_data(intent, true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
void _preload_data(intent, true);
// swallow rejections (e.g. AbortError when this preload is superseded and
// its controller is aborted) so they do not surface as unhandled rejections
void _preload_data(intent, true).catch(() => {});

In production builds, superseding an in-flight cancellable preload triggers an unhandled promise rejection (AbortError) because the non-DEV void _preload_data(intent, true) call has no .catch.

Fix on Vercel

@gcamargosilva
gcamargosilva marked this pull request as draft September 9, 2026 16:58
@gcamargosilva
gcamargosilva marked this pull request as ready for review September 9, 2026 17:39
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