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
- Create a fresh object literal in each render: `h('div', { attrs: {...} })`.
- Clone the needed values: `h('div', { ...this.cachedData })` or `JSON.parse(JSON.stringify(...))` for deep copies.
- Move the cached config out of reactive `data` into a non-reactive property or module-level constant.
- 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
- Never pass reactive data/props/store objects directly as the `h()` data argument.
- Spread or reconstruct vnode data inside render.
- Freeze static config objects with Object.freeze so Vue cannot observe them.
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
- $props is readonly.
- Avoid mutating an injected value directly since the changes
- 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
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/68e522fc0a2aed37.
Report an issue: GitHub.