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 `createElement` (the `h` function) expects a fresh plain object as the vnode's `data` argument. If the object passed is an observed reactive object (it has an `__ob__` property), Vue warns and renders an empty vnode instead, because reusing observed objects as vnode data corrupts patching.

Source

Thrown at packages/weex-vue-framework/factory.js:3713

    normalizationType = children;
    children = data;
    data = undefined;
  }
  if (isTrue(alwaysNormalize)) {
    normalizationType = ALWAYS_NORMALIZE;
  }
  return _createElement(context, tag, data, children, normalizationType)
}

function _createElement (
  context,
  tag,
  data,
  children,
  normalizationType
) {
  if (isDef(data) && isDef((data).__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

  1. Create a fresh object literal in each render: `h('div', { attrs: {...} })`.
  2. Clone the needed values: `h('div', { ...this.cachedData })` or `JSON.parse(JSON.stringify(...))` for deep copies.
  3. Move the cached config out of reactive `data` into a non-reactive property or module-level constant.
  4. Use `Object.freeze` on configuration objects so Vue never observes them (frozen objects get no `__ob__`).

Example fix

// before
h('div', this.nodeData)
// after
h('div', { attrs: { ...this.nodeData.attrs } })
Defensive patterns

Strategy: validation

Validate before calling

function assertFreshVnodeData(data) {
  if (data != null && data.__ob__) {
    throw new Error('Observed object passed as vnode data; create a fresh object');
  }
}

Type guard

function isObserved(obj) {
  return obj != null && typeof obj === 'object' && '__ob__' in obj;
}

Prevention

When it happens

Trigger: Returning a piece of reactive `data` (e.g. `h('div', this.someDataObject)`) or a store/props object that has been made reactive directly into the second argument of `h()`/`createElement`.

Common situations: Storing vnode-data templates in component data for reuse; passing Vuex state objects straight as vnode data; caching render metadata in reactive state after a refactor.

Related errors


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