{"record":{"id":"077859f7c684b5a2","repo":"Meituan-Dianping/mpvue","slug":"avoid-using-non-primitive-value-as-key-use-string-077859","errorCode":null,"errorMessage":"Avoid using non-primitive value as key, use string/number value instead.","messagePattern":"Avoid using non-primitive value as key, use string/number value instead\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/core/vdom/create-element.js","lineNumber":72,"sourceCode":"      `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\\n` +\n      'Always create fresh vnode data objects in each render!',\n      context\n    )\n    return createEmptyVNode()\n  }\n  // object syntax in v-bind\n  if (isDef(data) && isDef(data.is)) {\n    tag = data.is\n  }\n  if (!tag) {\n    // in case of component :is set to falsy value\n    return createEmptyVNode()\n  }\n  // warn against non-primitive key\n  if (process.env.NODE_ENV !== 'production' &&\n    isDef(data) && isDef(data.key) && !isPrimitive(data.key)\n  ) {\n    warn(\n      'Avoid using non-primitive value as key, ' +\n      'use string/number value instead.',\n      context\n    )\n  }\n  // support single function children as default scoped slot\n  if (Array.isArray(children) &&\n    typeof children[0] === 'function'\n  ) {\n    data = data || {}\n    data.scopedSlots = { default: children[0] }\n    children.length = 0\n  }\n  if (normalizationType === ALWAYS_NORMALIZE) {\n    children = normalizeChildren(children)\n  } else if (normalizationType === SIMPLE_NORMALIZE) {\n    children = simpleNormalizeChildren(children)\n  }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/Meituan-Dianping/mpvue/blob/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/src/core/vdom/create-element.js#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"Using whole API objects as keys; forgetting to key by `item.id`; iterating over arrays of objects in render functions or v-for.","solutions":["Key by a primitive identifier: `:key=\"item.id\"`","If no id exists, key by index `:key=\"index\"` (accepting reorder caveats) or generate a stable string key","Ensure objects carry a unique primitive field you can use as key"],"exampleFix":"// before\n<li v-for=\"item in items\" :key=\"item\">{{ item.name }}</li>\n// after\n<li v-for=\"item in items\" :key=\"item.id\">{{ item.name }}</li>","handlingStrategy":"validation","validationCode":"function assertPrimitiveKeys (items, keyOf) {\n  const bad = items.filter(it => {\n    const k = keyOf(it)\n    return k != null && (typeof k !== 'string' && typeof k !== 'number' && typeof k !== 'symbol')\n  })\n  if (bad.length) throw new TypeError('non-primitive v-for keys: ' + bad.length + ' item(s)')\n}","typeGuard":"function isPrimitiveKey (k) {\n  return k === null || (typeof k !== 'object' && typeof k !== 'function')\n}","tryCatchPattern":null,"preventionTips":["Always key lists by a primitive id field","Never pass whole objects as :key","Use index keys only as a last resort for static lists","Lint for :key=\"item\" patterns in v-for"],"tags":["vdom","v-for","key"],"backgroundTag":"non-primitive-vnode-key","analyzedSha":"6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b","analyzedAt":"2026-09-02T05:17:40.946Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T11:17:12.671Z"}