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

The `key` special attribute used for vnode diffing must be a string or number. Vue warns when a key is defined but not primitive (object/array/symbol-ish), because object identity keys break list reconciliation and cause incorrect reuse of elements.

Source

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

      "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. Use a unique primitive property: `:key="item.id"`.
  2. If no id exists, use index `:key="index"` (accepting reorder caveats) or generate a stable id when records are created.
  3. In render functions, pass `key: String(item.id)` in the data object.
  4. Combine fields into a string if a composite key is needed: `:key="item.type + '-' + item.id"`.

Example fix

// before
<div v-for="item in items" :key="item" />
// after
<div v-for="item in items" :key="item.id" />
Defensive patterns

Strategy: validation

Validate before calling

items.forEach(it => {
  if (it.key != null && !['string', 'number'].includes(typeof it.key)) {
    throw new TypeError('v-for key must be a string or number');
  }
});

Type guard

function isPrimitiveKey(k) {
  return k === null || ['string', 'number', 'boolean', 'symbol'].includes(typeof k);
}

Prevention

When it happens

Trigger: `<div v-for="item in items" :key="item">` where `item` is an object; `:key="{ id: 1 }"`; passing an object as `key` in a render function: `h(..., { key: someObject })`.

Common situations: Forgetting to drill into the object (`:key="item.id"`); using the whole record from an API response as key; iterating over arrays of objects without an id field.

Related errors


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