Meituan-Dianping/mpvue · error

$listeners is readonly.

Error message

$listeners is readonly.

What it means

Comes from the dev-only setter trap installed on $listeners in initRender. $listeners is the reactive, getter-only object of parent-declared event handlers (v-on bindings) on the component, refreshed by the framework whenever the parent re-renders. Code that does this.$listeners = ... or mutates it triggers this trap; such writes are discarded because the parent vnode's data is the single source of truth for these handlers.

Source

Thrown at src/core/instance/render.js:58

  // bind the createElement fn to this instance
  // so that we get proper render context inside it.
  // args order: tag, data, children, normalizationType, alwaysNormalize
  // internal version is used by render functions compiled from templates
  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  // normalization is always applied for the public version, used in
  // user-written render functions.
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

  // $attrs & $listeners are exposed for easier HOC creation.
  // they need to be reactive so that HOCs using them are always updated
  const parentData = parentVnode && parentVnode.data
  /* istanbul ignore else */
  if (process.env.NODE_ENV !== 'production') {
    defineReactive(vm, '$attrs', parentData && parentData.attrs, () => {
      !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
    }, true)
    defineReactive(vm, '$listeners', parentData && parentData.on, () => {
      !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
    }, true)
  } else {
    defineReactive(vm, '$attrs', parentData && parentData.attrs, null, true)
    defineReactive(vm, '$listeners', parentData && parentData.on, null, true)
  }
}

export function renderMixin (Vue: Class<Component>) {
  Vue.prototype.$nextTick = function (fn: Function) {
    return nextTick(fn, this)
  }

  Vue.prototype._render = function (): VNode {
    const vm: Component = this
    const {
      render,
      staticRenderFns,
      _parentVnode

View on GitHub (pinned to 6c5d78ee04)

Solutions

  1. Do not assign to this.$listeners; read it (e.g. v-on="$listeners" for HOC pass-through) only
  2. To add your own handlers, declare them with $emit/$on or merge them at template level: v-on="{ ...$listeners, click: handleClick }"
  3. To modify behavior, wrap listeners in computed properties instead of mutating the object
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at src/core/instance/render.js:58 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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