Meituan-Dianping/mpvue · warning

$props is readonly.

Error message

$props is readonly.

What it means

Vue dev-mode warning triggered by the $props setter installed in stateMixin. Props are owned by the parent component; mutating or replacing them from the child would break one-way data flow, so Vue makes $props read-only and warns on any assignment.

Source

Thrown at src/core/instance/state.js:305

export function stateMixin (Vue: Class<Component>) {
  // flow somehow has problems with directly declared definition object
  // when using Object.defineProperty, so we have to procedurally build up
  // the object here.
  const dataDef = {}
  dataDef.get = function () { return this._data }
  const propsDef = {}
  propsDef.get = function () { return this._props }
  if (process.env.NODE_ENV !== 'production') {
    dataDef.set = function (newData: Object) {
      warn(
        'Avoid replacing instance root $data. ' +
        'Use nested data properties instead.',
        this
      )
    }
    propsDef.set = function () {
      warn(`$props is readonly.`, this)
    }
  }
  Object.defineProperty(Vue.prototype, '$data', dataDef)
  Object.defineProperty(Vue.prototype, '$props', propsDef)

  Vue.prototype.$set = set
  Vue.prototype.$delete = del

  Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    const vm: Component = this
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {}

View on GitHub (pinned to 6c5d78ee04)

Solutions

  1. Assign to a local data property initialized from the prop, then mutate that
  2. Emit an event to the parent and let the parent update the prop
  3. Use a computed that transforms the prop instead of writing back to it

Example fix

// before
mounted() { this.$props.count = 0 }
// after
export default {
  props: ['count'],
  data() { return { localCount: this.count } }
}
Defensive patterns

Strategy: fallback

Validate before calling

function isPropWrite(vm, key) { return vm.$options && key in (vm.$options.props || {}) }

Type guard

function canAssignToInstance(vm, key) { return !(vm.$options && key in (vm.$options.props || {})) }

Prevention

When it happens

Trigger: this.$props = {...}; vm.$props.someProp = value; or generic code that loops over instance keys and assigns (e.g. deep-cloning state back onto the instance).

Common situations: Trying to 'localize' or edit prop values instead of copying them into data; deserialization/restore routines that blindly assign all collected keys; misunderstanding one-way data flow in child components.

Related errors


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