Meituan-Dianping/mpvue · warning

$props is readonly.

Error message

$props is readonly.

What it means

Vue exposes the component's props as a read-only `$props` object on the instance. In development builds, a setter is defined on `$props` that fires this warning if any code attempts to assign to it. Props are owned by the parent component, so mutating them from the child would break one-way data flow.

Source

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

function stateMixin (Vue) {
  // flow somehow has problems with directly declared definition object
  // when using Object.defineProperty, so we have to procedurally build up
  // the object here.
  var dataDef = {};
  dataDef.get = function () { return this._data };
  var propsDef = {};
  propsDef.get = function () { return this._props };
  if (process.env.NODE_ENV !== 'production') {
    dataDef.set = function (newData) {
      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,
    cb,
    options
  ) {
    var vm = this;
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {};

View on GitHub (pinned to 6c5d78ee04)

Solutions

  1. Remove the assignment to `this.$props`; treat it as strictly read-only.
  2. If you need local editable state seeded from props, copy into `data` (e.g. `data() { return { local: this.someProp } }`).
  3. To change a prop's value, emit an event to the parent (`this.$emit('update:x', v)`) or use `v-model`/`.sync` so the parent updates it.

Example fix

// before
this.$props = { ...this.$props, title: 'new' };
// after
this.$emit('update:title', 'new');
Defensive patterns

Strategy: validation

Validate before calling

if (import.meta.env.MODE !== 'production' && myCodeAssignsToProps) {
  throw new Error('Never assign to this.$props; emit an event instead');
}

Type guard

function isReadOnlyPropsRef(target) {
  return target && target.$props !== undefined && Object.getOwnPropertyDescriptor(Vue.prototype, '$props').set !== undefined;
}

Prevention

When it happens

Trigger: Any assignment like `this.$props = {...}`, `vm.$props.foo = x` triggering the setter (only the wholesale assignment triggers the setter), or destructuring-and-reassigning `$props` inside a component method, lifecycle hook, or mixin.

Common situations: Developers trying to 'reset' props after a parent update, old Vue 1.x code migrated to Vue 2 that mutated props directly, or generated/compiled render code accidentally writing to `$props`.

Related errors


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