Meituan-Dianping/mpvue · error
Avoid using observed data object as vnode data: ${JSON.strin
Error message
Avoid using observed data object as vnode data: ${JSON.stringify(data)}
Always create fresh vnode data objects in each render! What it means
Vue's virtual DOM patches by comparing vnode data objects. If the `data` argument passed to createElement (or h) is a reactive, observed object (it has an `__ob__` property), Vue refuses to use it because mutating/observing shared data across renders corrupts the patching process. It warns and renders an empty vnode instead, so the element silently disappears.
Source
Thrown at src/core/vdom/create-element.js:53
normalizationType = children
children = data
data = undefined
}
if (isTrue(alwaysNormalize)) {
normalizationType = ALWAYS_NORMALIZE
}
return _createElement(context, tag, data, children, normalizationType)
}
export function _createElement (
context: Component,
tag?: string | Class<Component> | Function | Object,
data?: VNodeData,
children?: any,
normalizationType?: number
): VNode {
if (isDef(data) && isDef((data: any).__ob__)) {
process.env.NODE_ENV !== 'production' && warn(
`Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
'Always create fresh vnode data objects in each render!',
context
)
return createEmptyVNode()
}
// object syntax in v-bind
if (isDef(data) && isDef(data.is)) {
tag = data.is
}
if (!tag) {
// in case of component :is set to falsy value
return createEmptyVNode()
}
// warn against non-primitive key
if (process.env.NODE_ENV !== 'production' &&
isDef(data) && isDef(data.key) && !isPrimitive(data.key)
) {View on GitHub (pinned to 6c5d78ee04)
Solutions
- Clone the object so it is plain: `h('div', { ...data })`
- Recreate the vnode data object inline in the render function on every call
- Strip reactivity with `JSON.parse(JSON.stringify(data))` if spreading is not enough (e.g. nested observed objects)
- If the object is intentionally static, freeze it before Vue observes it: `Object.freeze(data)`
Example fix
// before
render(h) {
return h('div', this.rowData) // rowData is reactive
}
// after
render(h) {
return h('div', { ...this.rowData })
} Defensive patterns
Strategy: validation
Validate before calling
function isObservedData (data) {
return data != null && typeof data === 'object' && '__ob__' in data
}
// before calling h():
if (isObservedData(data)) data = { ...data } Type guard
function isPlainObject (v) {
if (v === null || typeof v !== 'object') return false
const proto = Object.getPrototypeOf(v)
return proto === Object.prototype || proto === null
} Prevention
- Always build vnode data objects inline inside render functions
- Never store vnode data in reactive state or Vuex
- Spread cloned data when derived from observed sources
- Object.freeze truly static vnode data before Vue observes it
When it happens
Trigger: Calling `h(tag, someReactiveDataObject, children)` where the data object came from `data()` state, props, or a store getter, e.g. `h('div', this.attrsFromState)` in a render function or functional component.
Common situations: Spreading reactive component state into vnode data; reusing a cached vnode-data object stored in Vuex/redux-like state; programmatically building vnodes from observed API responses.
Related errors
- Avoid using observed data object as vnode data: ${JSON.strin
- Invalid handler for event "${event.name}": got ${String(cur)
- Avoid mutating a prop directly since the value will be overw
- Avoid replacing instance root $data. Use nested data propert
- $props is readonly.
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/a9f1f03f2745af67.
Report an issue: GitHub.