Meituan-Dianping/mpvue · error

Avoid using observed data object as vnode data

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.

Solutions

  1. Clone the object so it is plain: `h('div', { ...data })`
  2. Recreate the vnode data object inline in the render function on every call
  3. Strip reactivity with `JSON.parse(JSON.stringify(data))` if spreading is not enough (e.g. nested observed objects)
  4. 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

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


AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02). Data as JSON: /api/errors/a9f1f03f2745af67. Report an issue: GitHub.

Appendix: 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)