Skip to content

fix(teleport): don't move teleport children if in pending mount#14702

Open
lichunju1 wants to merge 2 commits intovuejs:mainfrom
lichunju1:fix/teleport-move-pending-mount
Open

fix(teleport): don't move teleport children if in pending mount#14702
lichunju1 wants to merge 2 commits intovuejs:mainfrom
lichunju1:fix/teleport-move-pending-mount

Conversation

@lichunju1
Copy link
Copy Markdown

@lichunju1 lichunju1 commented Apr 9, 2026

close #14701

Problem

When a disabled <Teleport> inside <Suspense> has its mount deferred via pendingMounts (introduced in #14642), component children have vnode.component === null because mountChildren was never called. During Suspense.resolve(), move(pendingBranch) walks the vnode tree and crashes on vnode.component.subTree for these unmounted components.

Reproduction: https://play.vuejs.org/#eNp9UstuwjAQ/JWVewAklKhqTyggtYhDq75UOPoSkgUMiW3ZDlCh/HvXDgFatdw8O7Pr2ceBPWgdbStkA5bYzAjtwKKr9IhLUWplHLyqvCoQFkaV0IniBvqUDpdJ3OSQmoDDUhepQ49cMq2sRmkbRPhYJ25xq4abRVoU8zTbjF5Umgu5jKIoiX8Wiy+qXXCsz5zNlFyIZbS2SlIXBy4BOMtUqUWB5l07oaTlbACB8Rx9p3bPIeZMhf02nq0w2/wRX9u9j3H2YdCi2SJnJ86lZomuoSfTN9zT+0SWoeWr5CdaVVTeYyN7rGROti90we1T2AXNZmYne0eDaJvyRr2yDnrOaC/jK62f7d5F9yGPy5qmeN7q/4dwgBXUxzto1s8lzd468D/CkAQGZY5mAN0eDEew6nZyse30/CdcprtUOLi9fjSkH42VpA5p5x6E6AwLDBacGnI2V/kXZ5ALm84LzNt78htXkhJhICzJvCmSNfeWxG2NXwdUfwNztgbg

Trigger conditions (all required):

  1. <Suspense> wrapping an async component (await in setup)
  2. Multi-root template (Fragment)
  3. <Teleport disabled> as a root sibling
  4. Component child (not element) inside the Teleport
  • 3.5.31: no error
  • 3.5.32: crash

Fix

Add a null check for vnode.component in the move function before accessing .subTree. Components with null instances are skipped — the deferred mount job handles their placement after Suspense flushes its effects.

Summary by CodeRabbit

Tests

  • Added test coverage for Suspense with disabled Teleports containing nested async components, validating fallback display and post-resolution rendering.

Bug Fixes

  • Fixed mounting of disabled Teleports within Suspense boundaries during async component resolution.
  • Improved teleport movement logic to account for pending mount operations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

Fixes a regression in Vue 3.5.32 where disabled Teleports containing component children inside Suspense-wrapped async components cause null reference errors. Modifies Teleport's deferred mount logic to use parentNode for correct container selection during Suspense resolution and prevents moving children when in pendingMounts state.

Changes

Cohort / File(s) Summary
Test Case
packages/runtime-core/__tests__/components/Suspense.spec.ts
Adds test for async component with multi-root template containing a disabled Teleport with component child; verifies fallback renders during pending state and content renders correctly after resolution.
Teleport Mount & Move Logic
packages/runtime-core/src/components/Teleport.ts
Extended internals.o with parentNode operation; modified deferred mount container selection to use `parentNode(vnode.el!)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

scope: teleport, scope: suspense, :hammer: p3-minor-bug

Poem

🐰 A teleport hung suspended in time,
When Suspense resolved, oh what a crime!
But parentNode whispers: "Follow me home,"
Now children mount safely, no more do they roam! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR addresses the primary objective from #14701: preventing the TypeError crash during Suspense.resolve() by guarding against null component instances, and includes the requested test case and fixes the stale container reference in deferred mount.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the regression: test case for the regression, null component check in move function, pendingMounts guard in moveTeleport, and stale container reference fix in deferred mount.
Title check ✅ Passed The PR title accurately describes the main fix: preventing teleport children from being moved when they are in a pending mount state, which is the core change in Teleport.ts and the solution to the crash described in the objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@edison1105
Copy link
Copy Markdown
Member

Could you please add a test case?

When a disabled Teleport inside Suspense has its mount deferred via
pendingMounts, component children have vnode.component === null
because mountChildren was never called. During Suspense.resolve(),
move(pendingBranch) walks the tree and crashes on
vnode.component.subTree for these unmounted components.

Add a null check for vnode.component in the move function to skip
components that have not been mounted yet. The deferred mount job
will handle their placement after Suspense flushes its effects.

close vuejs#14701
@lichunju1 lichunju1 force-pushed the fix/teleport-move-pending-mount branch from 32c90bb to aaa59da Compare April 9, 2026 17:29
@lichunju1
Copy link
Copy Markdown
Author

Could you please add a test case?

Done — added a test case and also fixed the stale container reference in the deferred mount job. Please take a look.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 10, 2026

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 105 kB (+45 B) 39.9 kB (+22 B) 35.8 kB (+8 B)
vue.global.prod.js 164 kB (+45 B) 59.9 kB (+19 B) 53.2 kB (+6 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 48.3 kB 18.8 kB 17.2 kB
createApp 56.5 kB 21.8 kB 20 kB
createSSRApp 60.7 kB 23.6 kB 21.5 kB
defineCustomElement 62.6 kB 23.8 kB 21.7 kB
overall 71 kB 27.2 kB 24.7 kB

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 10, 2026

Open in StackBlitz

@vue/compiler-core

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

@vue/compiler-dom

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

@vue/compiler-sfc

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

@vue/compiler-ssr

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

@vue/reactivity

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

@vue/runtime-core

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

@vue/runtime-dom

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

@vue/server-renderer

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

@vue/shared

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

vue

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

@vue/compat

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

commit: 0d767cd

@edison1105
Copy link
Copy Markdown
Member

edison1105 commented Apr 10, 2026

Thanks for the PR.
The proper fix should avoid moving teleport children if in the pending mount.
see 0d767cd

@edison1105
Copy link
Copy Markdown
Member

/ecosystem-ci run

@edison1105 edison1105 changed the title fix(teleport): guard against null component instance during move fix(teleport): don't move teleport children if in pending mount Apr 10, 2026
@edison1105 edison1105 added scope: teleport 🔨 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. labels Apr 10, 2026
@lichunju1
Copy link
Copy Markdown
Author

Thanks for the PR. The proper fix should avoid moving teleport children if in the pending mount. see 0d767cd

Thanks for the refinement! Guarding at the moveTeleport entry is a more precise fix. Learned a lot from this PR.

@vue-bot
Copy link
Copy Markdown
Contributor

vue-bot commented Apr 10, 2026

📝 Ran ecosystem CI: Open

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

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: teleport

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Teleport] TypeError: Cannot read properties of null (reading 'subTree') during Suspense resolve — regression in 3.5.32

3 participants