Meituan-Dianping/mpvue · error
The client-side rendered virtual DOM tree is not matching se
Error message
The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
What it means
During SSR hydration, the client-generated virtual DOM tree did not match the server-rendered HTML at the same position. Vue abandons hydration entirely and performs a full client-side re-render, which can cause a visible flash/reflow and lost server-render benefits.
Source
Thrown at src/core/vdom/patch.js:627
const isRealElement = isDef(oldVnode.nodeType)
if (!isRealElement && sameVnode(oldVnode, vnode)) {
// patch existing root node
patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly)
} else {
if (isRealElement) {
// mounting to a real element
// check if this is server-rendered content and if we can perform
// a successful hydration.
if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
oldVnode.removeAttribute(SSR_ATTR)
hydrating = true
}
if (isTrue(hydrating)) {
if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
invokeInsertHook(vnode, insertedVnodeQueue, true)
return oldVnode
} else if (process.env.NODE_ENV !== 'production') {
warn(
'The client-side rendered virtual DOM tree is not matching ' +
'server-rendered content. This is likely caused by incorrect ' +
'HTML markup, for example nesting block-level elements inside ' +
'<p>, or missing <tbody>. Bailing hydration and performing ' +
'full client-side render.'
)
}
}
// either not server-rendered, or hydration failed.
// create an empty node and replace it
oldVnode = emptyNodeAt(oldVnode)
}
// replacing existing element
const oldElm = oldVnode.elm
const parentElm = nodeOps.parentNode(oldElm)
createElm(
vnode,
insertedVnodeQueue,View on GitHub (pinned to 6c5d78ee04)
Solutions
- Make server and client render identical output: move non-deterministic values (time, random, window checks) into `mounted` or wrap in `<client-only>`
- Fix invalid HTML nesting (no block elements inside `<p>`; include `<tbody>` in tables)
- Diff the server HTML against the client render to find the first mismatch (Vue devtools or console inspection)
- As a last resort accept the warning — Vue still renders correctly client-side, just without hydration benefits
Example fix
// before <p><div v-if="wide">wide</div></p> // after <div><div v-if="wide">wide</div></div>
Defensive patterns
Strategy: fallback
Validate before calling
// pre-render sanity check for SSR determinism
function assertDeterministicRender (renderFn) {
const a = renderFn(), b = renderFn()
if (JSON.stringify(a) !== JSON.stringify(b)) {
console.warn('render is non-deterministic — hydration will mismatch')
}
} Try / catch
// hydration is not thrown, but you can detect the bail-out:
mounted () {
this.$nextTick(() => {
if (this.$el.dataset && this.$el.dataset.serverRendered === undefined) {
console.warn('hydration bailed; full client render occurred')
}
})
} Prevention
- Avoid Date.now(), Math.random(), and window checks in render/template
- Wrap browser-only content in <client-only> or render after mounted
- Keep server HTML valid (no block-in-<p>, always <tbody>)
- Test SSR output vs client render in CI
When it happens
Trigger: Server and client render different markup: date/`Date.now()`/random values, browser-only conditionals (`typeof window !== 'undefined'`), invalid HTML nesting that the browser rewrites (block elements inside `<p>`, tables missing `<tbody>`), whitespace/attribute differences, different v-for lengths.
Common situations: Nuxt/SSR apps rendering timestamps or locale-dependent strings; browser auto-correcting malformed server HTML so the client's parsed tree differs; user-agent-dependent markup; mismatched component state hydrated incorrectly.
Related errors
- Avoid using observed data object as vnode data: ${JSON.strin
- Avoid using non-primitive value as key, use string/number va
- Duplicate presence of slot "${name}" found in the same rende
- Avoid using observed data object as vnode data: ${JSON.strin
- Avoid using non-primitive value as key, use string/number va
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/5f600fa5ab80028b.
Report an issue: GitHub.