Skip to content

fix: {#await await ...} and async dependencies fixes#18243

Merged
Rich-Harris merged 6 commits into
mainfrom
await-unset-fix
May 19, 2026
Merged

fix: {#await await ...} and async dependencies fixes#18243
Rich-Harris merged 6 commits into
mainfrom
await-unset-fix

Conversation

@dummdidumm

Copy link
Copy Markdown
Member

This started out as an investigation to get rid of the runtime code for {#await ...} that deactivated a batch prior to reading the promise function. That can result in a new batch being created if the promise invocation happens to write a source.

Through that I discovered two other bugs:

  1. The way we handle {#await await ...} was flawed around SSR/hydration: On the server it would await the expression (which it should not; {#await await ...} is kind of a weird special case here) and during hydration it did not produce matching nodes, leading to hydration fails.
  2. When reading a dependency after an await expression which we add to the current reaction, we did not deduplicate those reads. That can lead to duplicate dependencies, which in turn can lead to bugs when remove_reaction later runs. Conside this: You have deps = [count, unrelated, count]. Now you do remove_reactions(deps, 1), i.e. "remove all reactions after the first one". That means the "disconnect these from each other" logic runs for count, too, because it's also in the third position, but that is wrong because it is also in the first position, i.e. the connection should be kept.

Investigating reports of unresponsive reactivity in non-async-mode. No clear culprit yet but found that `#merge` can be called wrongfully. Part of the reason for that is that we are unsetting the current batch prior to invoking the `{#await ...}` promise. This can result in writes going into a different batch while traversal is happening, which can cause weird downstream effects.

No test because not sure what to test here what can go wrong specifically, but it certainly _feels_ wrong.

Also added a few test labels which helped when debugging.
@changeset-bot

changeset-bot Bot commented May 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1952dd2

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

This PR includes changesets to release 1 package
Name Type
svelte 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

@svelte-docs-bot

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Playground

pnpm add https://pkg.pr.new/svelte@18243

);

if (node.metadata.expression.has_blockers()) {
if (node.metadata.expression.has_blockers() || node.metadata.expression.has_await) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is this change necessary? AFAICT it just results in unnecessary $.async(...) wrappers in the {#await await ...} case

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Just checked again - it is necessary, if you e.g. have two consecutive awaits it fails with a hydration error:

{#await await 1 then result}{result}{/await}
{#await await 1 then result}{result}{/await}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

any idea how we can add a regression test for this? i tried just now but it's curiously difficult to assert that a hydration mismatch occurs, unless i'm doing something daft

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh nvm you already did

Comment thread packages/svelte/src/internal/client/dom/blocks/await.js Outdated
@Rich-Harris Rich-Harris merged commit 000c594 into main May 19, 2026
21 checks passed
@Rich-Harris Rich-Harris deleted the await-unset-fix branch May 19, 2026 20:16
@github-actions github-actions Bot mentioned this pull request May 19, 2026
dummdidumm pushed a commit that referenced this pull request May 20, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## svelte@5.55.9

### Patch Changes

- fix: don't unset batch when calling `{#await ...}` promise
([#18243](#18243))

- fix: promise-ify `{#await await ...}` expressions on the server and
correctly hydrate them on the client
([#18243](#18243))

- fix: deduplicate dependencies that are added outside the init/update
cycle ([#18243](#18243))

- fix: avoid false-positive batch invariant error
([#18246](#18246))

- fix: inline primitive constants in attribute values during SSR
([#18232](#18232))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants