Meituan-Dianping/mpvue · warning
Avoid adding reactive properties to a Vue instance or its ro
Error message
Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.
What it means
Warning from Vue.set / vm.$set (set in observer/index.js) when the target is a Vue instance or the root $data object. Adding properties to these at runtime cannot be made reactive reliably, so Vue warns and returns the value without making it reactive.
Source
Thrown at src/core/observer/index.js:238
/**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*/
export function set (target: Array<any> | Object, key: any, val: any): any {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
if (hasOwn(target, key)) {
target[key] = val
return val
}
const ob = (target: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
)
return val
}
if (!ob) {
target[key] = val
return val
}
defineReactive(ob.value, key, val)
// Vue.set 添加对象属性,渲染时候把 val 传给小程序渲染
if (!target.__keyPath) {
def(target, '__keyPath', {}, false)
}
target.__keyPath[key] = true
ob.dep.notify()
return val
}View on GitHub (pinned to 6c5d78ee04)
Solutions
- Declare all keys upfront in the data() option, even with placeholder values
- If the set of keys is dynamic, nest them: data(){return{fields:{}}} and Vue.set(this.fields, key, val)
- Restructure dynamic items into arrays, which Vue can react to via splice/push
- If purely non-reactive metadata is needed, store it on this outside data and skip reactivity
Example fix
// before
this.$set(this.$data, 'field_' + i, '')
// after
export default {
data() { return { fields: {} } },
methods: { addField(i) { this.$set(this.fields, 'field_' + i, '') } }
} Defensive patterns
Strategy: validation
Validate before calling
function isSafeSetTarget(target) {
return target != null && typeof target === 'object' && !target._isVue && !(target.__ob__ && target.__ob__.vmCount)
}
// only call Vue.set when isSafeSetTarget(target) Type guard
function isVueInstanceOrRootData(t) { return t != null && (t._isVue === true || (t.__ob__ && t.__ob__.vmCount > 0)) } Prevention
- Declare every reactive key in data() upfront
- Keep dynamic keys in a nested object, not at $data root
- Add keys to arrays via push/splice which Vue observes
When it happens
Trigger: Vue.set(vm, 'newKey', value); Vue.set(this.$data, 'newKey', value); this.$set(this.$data, key, val) for dynamic form fields; assigning new keys onto vm directly after creation and expecting reactivity.
Common situations: Dynamic form schemas adding fields after mount; generic key/value editors bound directly to $data; plugins attempting to extend instances post-creation instead of at init.
Related errors
- Avoid deleting properties on a Vue instance or its root $dat
- Avoid mutating a prop directly since the value will be overw
- Avoid replacing instance root $data. Use nested data propert
- $props is readonly.
- Avoid mutating an injected value directly since the changes
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/6c479ac024f96c1d.
Report an issue: GitHub.