Skip to content

fix(reactivity): keep subscribers alive after a computed throws - #16175

Open
ondrhn wants to merge 1 commit into
vuejs:minorfrom
ondrhn:fix/issue-16173-reactivity-keep-subscribers
Open

ondrhn wants to merge 1 commit into
vuejs:minorfrom
ondrhn:fix/issue-16173-reactivity-keep-subscribers

Conversation

@ondrhn

@ondrhn ondrhn commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Once a watched computed's getter throws, the subscriber is dead for good: with s = ref(0), c = computed(() => s.value === 1 ? throw : s.value) and watch(c, cb), setting s to 1 throws as expected, but the later writes s = 2 and s = 3 never reach the callback. 3.5.45 reports the error and keeps delivering 2 and 3. The same happens for a plain effect, for a chain of computeds, and for an effect with a custom scheduler (the script in the issue logs [0] instead of [0, 2, 3]).

Two things go wrong. checkDirty() in system.ts refreshes stale computeds in place, and when (dep as Computed).update() or the (sub as Computed).update() in the unwinding loop throws, the function is left through the exception with the Pending flag that propagate() set still on the subscriber and on every intermediate computed on the check chain; the next propagate() sees those flags, decides the node is already queued and neither notifies it nor descends into its own subscribers. Wrapping the walk in try/catch and clearing Pending on sub, link.sub and the remaining stack entries before rethrowing restores the 3.5 behaviour — the failing step is lost, the error is reported, the following ones run. Separately, ComputedRefImpl.get value() in computed.ts calls link() after update(), so a subscriber that reads the computed inside run() (custom scheduler, first render, first watch run) never records the dep and endTracking() unlinks it; the tracking block now sits in a try { … } finally { link(…) } so the link survives a throwing getter, which is what dep.track()-before-evaluate gave us in 3.5.

Catching inside the effect.ts and computed.ts getters instead would have been a smaller diff, but it cannot clear the Pending flag left on intermediate computeds, so the chained case stays broken. Sibling fix in the same area: ef5ff10 (#15676), which kept the rest of a batch notified when one subscriber throws.

fix #16173

checkDirty() left the Pending flag set on the subscribers it was walking
when a computed's getter threw, so later propagate() calls treated them
as already queued and never notified them again. Also link the computed
to the active subscriber even when the getter throws, otherwise
endTracking() drops the dep on the first failing read.
@coderabbitai

coderabbitai Bot commented Nov 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e51c5e76-1232-43b6-8c2e-6ec5409c7eb8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pkg-pr-new

pkg-pr-new Bot commented Nov 7, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@16175
npm i https://pkg.pr.new/@vue/compiler-core@16175
yarn add https://pkg.pr.new/@vue/compiler-core@16175.tgz

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@16175
npm i https://pkg.pr.new/@vue/compiler-dom@16175
yarn add https://pkg.pr.new/@vue/compiler-dom@16175.tgz

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@16175
npm i https://pkg.pr.new/@vue/compiler-sfc@16175
yarn add https://pkg.pr.new/@vue/compiler-sfc@16175.tgz

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@16175
npm i https://pkg.pr.new/@vue/compiler-ssr@16175
yarn add https://pkg.pr.new/@vue/compiler-ssr@16175.tgz

@vue/compiler-vapor

pnpm add https://pkg.pr.new/@vue/compiler-vapor@16175
npm i https://pkg.pr.new/@vue/compiler-vapor@16175
yarn add https://pkg.pr.new/@vue/compiler-vapor@16175.tgz

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@16175
npm i https://pkg.pr.new/@vue/reactivity@16175
yarn add https://pkg.pr.new/@vue/reactivity@16175.tgz

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@16175
npm i https://pkg.pr.new/@vue/runtime-core@16175
yarn add https://pkg.pr.new/@vue/runtime-core@16175.tgz

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@16175
npm i https://pkg.pr.new/@vue/runtime-dom@16175
yarn add https://pkg.pr.new/@vue/runtime-dom@16175.tgz

@vue/runtime-vapor

pnpm add https://pkg.pr.new/@vue/runtime-vapor@16175
npm i https://pkg.pr.new/@vue/runtime-vapor@16175
yarn add https://pkg.pr.new/@vue/runtime-vapor@16175.tgz

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@16175
npm i https://pkg.pr.new/@vue/server-renderer@16175
yarn add https://pkg.pr.new/@vue/server-renderer@16175.tgz

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@16175
npm i https://pkg.pr.new/@vue/shared@16175
yarn add https://pkg.pr.new/@vue/shared@16175.tgz

vue

pnpm add https://pkg.pr.new/vue@16175
npm i https://pkg.pr.new/vue@16175
yarn add https://pkg.pr.new/vue@16175.tgz

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@16175
npm i https://pkg.pr.new/@vue/compat@16175
yarn add https://pkg.pr.new/@vue/compat@16175.tgz

commit: 23dee1f

@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
compiler-dom.global.prod.js 87.4 kB 30.7 kB 27 kB
runtime-dom.global.prod.js 123 kB (+112 B) 46.1 kB (+33 B) 41.3 kB (+72 B)
vue.global.prod.js 183 kB (+112 B) 66.4 kB (+35 B) 59.1 kB (+11 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 54.8 kB (+100 B) 21.3 kB (+31 B) 19.5 kB (+3 B)
createApp 63.8 kB (+112 B) 24.6 kB (+40 B) 22.4 kB (+34 B)
createApp + vaporInteropPlugin 118 kB (+112 B) 43.3 kB (+29 B) 39 kB (+39 B)
createVaporApp 34.3 kB (+100 B) 13.3 kB (+33 B) 12.2 kB (+36 B)
createSSRApp 68.7 kB (+112 B) 26.6 kB (+36 B) 24.2 kB (+28 B)
createVaporSSRApp 42.1 kB (+100 B) 16.1 kB (+29 B) 14.8 kB (-17 B)
defineCustomElement 70.3 kB (+112 B) 26.6 kB (+41 B) 24.2 kB (+37 B)
defineVaporCustomElement 49.4 kB (+100 B) 18.1 kB (+30 B) 16.6 kB (+25 B)
overall 80.7 kB (+112 B) 30.6 kB (+28 B) 27.7 kB (-24 B)

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