Skip to content

fix: disallow effect creation after await#18299

Merged
dummdidumm merged 7 commits into
mainfrom
revert-18289-effect-root-async-update-fix
May 27, 2026
Merged

fix: disallow effect creation after await#18299
dummdidumm merged 7 commits into
mainfrom
revert-18289-effect-root-async-update-fix

Conversation

@Rich-Harris

@Rich-Harris Rich-Harris commented May 26, 2026

Copy link
Copy Markdown
Member

We incorrectly restore effect context after an$derived(await ...) if it occurs inside an async function, but only for those, no other await expressions. This is buggy and wrong. We only want to restore context inside an async derived expression (including template expressions)so thatawait a + b` works correctly.

It's possible that this will be a breaking change (albeit not semver-violating, because experimental) for some people if they are creating effects after an await (other than at the top level of a component). This is regrettable, but it should never have worked in the first place.

@changeset-bot

changeset-bot Bot commented May 26, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8d63f70

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@github-actions

Copy link
Copy Markdown
Contributor

Playground

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

@svelte-docs-bot

Copy link
Copy Markdown

@Rich-Harris Rich-Harris changed the title Revert "fix: don't assume boundary exists during increment/decrement" fix: disallow effect creation after await May 27, 2026
@Rich-Harris Rich-Harris marked this pull request as ready for review May 27, 2026 02:44
@dummdidumm

dummdidumm commented May 27, 2026

Copy link
Copy Markdown
Member

I think we've discovered something majorly broken here, and maybe made it worse on main?

  • latest released version: clicking "other" increments only the count that is initialized in the template and the one with top-level await (but no template await). Once I click "increment" nothing is reactive anymore
  • main: almost nothing works anymore (same on this PR)

My original idea for making this playground was to show that removing wait from these deriveds can result in the wrong values being used: If you are newly creating this function as part of an async batch, but then don't reapply it, the values afterwards will not read the value that this batch sees, instead they read the latest version. If there are multiple batches going, this can result in tearing/wrong values. But as you can see I didn't even get that far.

@Rich-Harris

Copy link
Copy Markdown
Member Author

I notice that these...

{(await x).value}
{(await y).value}
{y.value}
{(await fn()).value}

...aren't being transformed to use $.save(...):

$.template_effect(
	// ...
	[
		async () => (await x).value,
		async () => (await y).value,
		async () => (await fn()).value
	],
	// ...
);

So when .value is read, we're no longer in an effect context. By extension, combined is never connected to the effect tree, so changes to its dependencies don't cause effects to reschedule.

Other than that, I think the behaviour in this PR is an improvement on main, at least insofar as it's consistent (the behaviour doesn't change after you first increment).

@Rich-Harris

Copy link
Copy Markdown
Member Author

(This, incidentally, is also the source of the await_reactivity_loss warning)

@Rich-Harris

Copy link
Copy Markdown
Member Author

Think I just fixed it, but about to jump on a call so will add a test later

@Rich-Harris

Copy link
Copy Markdown
Member Author

Still broken, but differently — other updates everything, until you click increment which severs the link

@Rich-Harris

Copy link
Copy Markdown
Member Author

Haven't fully figured this out but I think it's at least partly because count belongs to the effect, and thus isn't treated as a dependency of the effect. So it's not something that we should expect to work.

Since it's tangential to the main purpose of this PR, and since we're in a better state here than we were on main even if it's not fully resolved, my inclination would be to merge this and file it under 'weird edge cases to look into later'

@dummdidumm dummdidumm left a comment

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.

agreed - though I'm not sure if it's the "created inside effect" case, because in async mode that does trigger (we changed that)

@dummdidumm dummdidumm merged commit 0da9f9e into main May 27, 2026
30 of 31 checks passed
@dummdidumm dummdidumm deleted the revert-18289-effect-root-async-update-fix branch May 27, 2026 19:59
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