{"record":{"id":"43c68e83689e5cd5","repo":"Meituan-Dianping/mpvue","slug":"avoid-using-non-primitive-value-as-key-use-string","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":"packages/weex-vue-framework/factory.js","lineNumber":3732,"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":3714,"sourceCodeEnd":3750,"githubUrl":"https://github.com/Meituan-Dianping/mpvue/blob/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/packages/weex-vue-framework/factory.js#L3714-L3750","documentation":"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.","triggerScenarios":"`<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 })`.","commonSituations":"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.","solutions":["Use a unique primitive property: `:key=\"item.id\"`.","If no id exists, use index `:key=\"index\"` (accepting reorder caveats) or generate a stable id when records are created.","In render functions, pass `key: String(item.id)` in the data object.","Combine fields into a string if a composite key is needed: `:key=\"item.type + '-' + item.id\"`."],"exampleFix":"// before\n<div v-for=\"item in items\" :key=\"item\" />\n// after\n<div v-for=\"item in items\" :key=\"item.id\" />","handlingStrategy":"validation","validationCode":"items.forEach(it => {\n  if (it.key != null && !['string', 'number'].includes(typeof it.key)) {\n    throw new TypeError('v-for key must be a string or number');\n  }\n});","typeGuard":"function isPrimitiveKey(k) {\n  return k === null || ['string', 'number', 'boolean', 'symbol'].includes(typeof k);\n}","tryCatchPattern":null,"preventionTips":["Always key v-for items by a stable primitive id (`item.id`).","Ensure API records carry an id; generate one client-side if absent.","Never bind the iterated object itself as the key."],"tags":["vue","v-for","key","vdom","dev-warning"],"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"}