Skip to content

fix(reactivity): handle effect removal during scope stop#15084

Merged
edison1105 merged 2 commits into
vuejs:mainfrom
Askerka00:fix/effect-scope-traversal-crash
Jul 16, 2026
Merged

fix(reactivity): handle effect removal during scope stop#15084
edison1105 merged 2 commits into
vuejs:mainfrom
Askerka00:fix/effect-scope-traversal-crash

Conversation

@Askerka00

@Askerka00 Askerka00 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes a runtime crash in EffectScope (TypeError: Cannot read properties of undefined).

Cause

When a parent scope stops, pauses, or resumes, it iterates over this.scopes using a cached length. If a child's cleanup callback (onScopeDispose) stops a sibling scope, the sibling removes itself from parent.scopes dynamically. This shrinks the array, causing the parent loop to access an out-of-bounds index (undefined) and crash.

Fix

We now create a shallow copy of this.scopes using .slice() before iterating in pause(), resume(), and stop() methods. This ensures that any dynamic array mutations during traversal do not break the loop.

fixes #15083

Summary by CodeRabbit

  • Bug Fixes
    • Improved EffectScope lifecycle handling so pausing, resuming, and stopping remain reliable even if child scopes or watchers are added/removed during the process.
    • Added test coverage for scenarios involving sibling scope/watcher cleanup while scopes are paused or being resumed, preventing errors and ensuring correct inactive behavior.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

EffectScope.pause(), resume(), and stop() now traverse snapshots of child scopes, while resume() also snapshots effects. Tests cover collection mutations during cleanup and watcher resumption.

Changes

Effect scope traversal

Layer / File(s) Summary
Snapshot lifecycle collections
packages/reactivity/src/effectScope.ts
Lifecycle methods iterate over shallow snapshots of child scopes and, during resume, effects.
Validate mutating lifecycle operations
packages/reactivity/__tests__/effectScope.spec.ts
Tests verify safe sibling-scope cleanup and correct watcher behavior when effects are removed during resume.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested labels: scope: reactivity, :exclamation: p4-important

Suggested reviewers: edison1105

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code fixes the reported scope traversal crash and adds tests covering the linked stop/pause/resume mutations.
Out of Scope Changes check ✅ Passed The changes stay within the reported EffectScope traversal bug and its lifecycle coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main runtime fix in EffectScope traversal during stop operations.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands.

@Askerka00 Askerka00 force-pushed the fix/effect-scope-traversal-crash branch from c002bad to 59c0866 Compare July 14, 2026 17:31
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 107 kB (+25 B) 40.3 kB (+3 B) 36.2 kB (+8 B)
vue.global.prod.js 165 kB (+25 B) 60.4 kB (+4 B) 53.7 kB (+28 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 49 kB (+25 B) 19 kB (+1 B) 17.4 kB (+1 B)
createApp 57.1 kB (+25 B) 22.1 kB (+4 B) 20.2 kB (+10 B)
createSSRApp 61.6 kB (+25 B) 23.9 kB (-1 B) 21.8 kB (+6 B)
defineCustomElement 63.3 kB (+25 B) 24 kB (+3 B) 21.9 kB (+4 B)
overall 71.9 kB (+25 B) 27.5 kB (+2 B) 25 kB (-57 B)

@pkg-pr-new

pkg-pr-new Bot commented Jul 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vue/compiler-core

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

@vue/compiler-dom

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

@vue/compiler-sfc

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

@vue/compiler-ssr

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

@vue/reactivity

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

@vue/runtime-core

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

@vue/runtime-dom

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

@vue/server-renderer

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

@vue/shared

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

vue

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

@vue/compat

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

commit: 300bc2f

@edison1105 edison1105 added ready to merge The PR is ready to be merged. scope: reactivity 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. labels Jul 15, 2026
@edison1105 edison1105 changed the title fix: effect scope traversal crash fix(reactivity): handle effect removal during scope stop Jul 15, 2026
@edison1105

Copy link
Copy Markdown
Member

/ecosystem-ci run

@vue-bot

vue-bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

📝 Ran ecosystem CI: Open

suite result latest scheduled
primevue success success
language-tools success success
radix-vue success success
quasar success success
pinia success success
nuxt success success
vant success success
router success success
test-utils success success
vitepress success success
vueuse success success
vue-macros success success
vuetify success success
vue-i18n success success
vue-simple-compiler success success
vite-plugin-vue success success

@edison1105 edison1105 merged commit 378f978 into vuejs:main Jul 16, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. ready to merge The PR is ready to be merged. scope: reactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EffectScope stop() causes runtime crash (Cannot read properties of undefined) when dynamic scope cleanup mutates parent.scopes array during traversal

3 participants