{"record":{"id":"e75cd9709927d2cd","repo":"Meituan-Dianping/mpvue","slug":"template-cannot-be-keyed-place-the-key-on-real","errorCode":null,"errorMessage":"<template> cannot be keyed. Place the key on real elements instead.","messagePattern":"<template> cannot be keyed\\. Place the key on real elements instead\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/weex-template-compiler/build.js","lineNumber":1628,"sourceCode":"  if (l) {\n    var attrs = el.attrs = new Array(l);\n    for (var i = 0; i < l; i++) {\n      attrs[i] = {\n        name: el.attrsList[i].name,\n        value: JSON.stringify(el.attrsList[i].value)\n      };\n    }\n  } else if (!el.pre) {\n    // non root node in pre blocks with no attributes\n    el.plain = true;\n  }\n}\n\nfunction processKey (el) {\n  var exp = getBindingAttr(el, 'key');\n  if (exp) {\n    if (process.env.NODE_ENV !== 'production' && el.tag === 'template') {\n      warn(\"<template> cannot be keyed. Place the key on real elements instead.\");\n    }\n    el.key = exp;\n  }\n}\n\nfunction processRef (el) {\n  var ref = getBindingAttr(el, 'ref');\n  if (ref) {\n    el.ref = ref;\n    el.refInFor = checkInFor(el);\n  }\n}\n\nfunction processFor (el) {\n  var exp;\n  if ((exp = getAndRemoveAttr(el, 'v-for'))) {\n    var inMatch = exp.match(forAliasRE);\n    if (!inMatch) {","sourceCodeStart":1610,"sourceCodeEnd":1646,"githubUrl":"https://github.com/Meituan-Dianping/mpvue/blob/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/packages/weex-template-compiler/build.js#L1610-L1646","documentation":"A key binding was placed on a <template> element. Because <template> is an abstract wrapper that renders no element of its own (and v-for on template renders its children), a key there is meaningless; the compiler warns and points you to put the key on the real rendered elements instead.","triggerScenarios":"Using key with template, e.g. <template v-for=\"item in list\" :key=\"item.id\">...</template> — processKey detects el.tag === 'template' with a bound key in dev mode.","commonSituations":"Migrating list rendering code where the key belonged on an inner element, or applying :key habitually to every element with v-for including template wrappers (note: valid in Vue 3, warned in Vue 2).","solutions":["Move the :key binding from <template> to the real root element(s) inside it","If children have no single root, wrap them in a keyed real element","Upgrade consideration: Vue 3 allows keys on template v-for, so this warning is Vue 2-specific"],"exampleFix":"// before\n<template v-for=\"item in items\" :key=\"item.id\">\n  <li>{{ item.text }}</li>\n</template>\n// after\n<template v-for=\"item in items\">\n  <li :key=\"item.id\">{{ item.text }}</li>\n</template>","handlingStrategy":"validation","validationCode":"function keyOnTemplate(template) {\n  return /<template[^>]*\\s(?::key|v-bind:key)\\s*=/.test(template)\n    ? 'key found on <template>; move it to real elements'\n    : null;\n}","typeGuard":"function hasNoTemplateKey(template) {\n  return typeof template === 'string' && !/<template[^>]*\\s(?::key|v-bind:key|key)\\s*=/.test(template);\n}","tryCatchPattern":null,"preventionTips":["Put :key on real elements inside template v-for loops","Add eslint-plugin-vue rule vue/require-v-for-key + no-use-v-if-with-v-for style checks","Remember this is Vue 2 semantics; Vue 3 permits keyed template v-for"],"tags":["template","v-for","key","vue","weex"],"backgroundTag":"key-on-template-element","analyzedSha":"6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b","analyzedAt":"2026-09-02T05:17:40.946Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T11:17:12.671Z"}