Meituan-Dianping/mpvue · warning

Avoid using non-primitive value as key, use string/number va

Error message

Avoid using non-primitive value as key, use string/number value instead.

What it means

Vue uses list keys to match old and new vnodes during patching. A non-primitive key (object/array) cannot be compared reliably, so Vue warns that the key is useless and falls back to treating it as undefined, causing inefficient or incorrect list updates.

Source

Thrown at src/core/vdom/create-element.js:72

      `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)
  ) {
    warn(
      'Avoid using non-primitive value as key, ' +
      'use string/number value instead.',
      context
    )
  }
  // support single function children as default scoped slot
  if (Array.isArray(children) &&
    typeof children[0] === 'function'
  ) {
    data = data || {}
    data.scopedSlots = { default: children[0] }
    children.length = 0
  }
  if (normalizationType === ALWAYS_NORMALIZE) {
    children = normalizeChildren(children)
  } else if (normalizationType === SIMPLE_NORMALIZE) {
    children = simpleNormalizeChildren(children)
  }

View on GitHub (pinned to 6c5d78ee04)

Solutions

  1. Key by a primitive identifier: `:key="item.id"`
  2. If no id exists, key by index `:key="index"` (accepting reorder caveats) or generate a stable string key
  3. Ensure objects carry a unique primitive field you can use as key

Example fix

// before
<li v-for="item in items" :key="item">{{ item.name }}</li>
// after
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
Defensive patterns

Strategy: validation

Validate before calling

function assertPrimitiveKeys (items, keyOf) {
  const bad = items.filter(it => {
    const k = keyOf(it)
    return k != null && (typeof k !== 'string' && typeof k !== 'number' && typeof k !== 'symbol')
  })
  if (bad.length) throw new TypeError('non-primitive v-for keys: ' + bad.length + ' item(s)')
}

Type guard

function isPrimitiveKey (k) {
  return k === null || (typeof k !== 'object' && typeof k !== 'function')
}

Prevention

When it happens

Trigger: Rendering a v-for / list of vnodes with `:key="item"` or `h('li', { key: item }, ...)` where `item` is an object rather than a string/number.

Common situations: Using whole API objects as keys; forgetting to key by `item.id`; iterating over arrays of objects in render functions or v-for.

Related errors


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