Meituan-Dianping/mpvue · warning

<template> cannot be keyed. Place the key on real elements i

Error message

<template> cannot be keyed. Place the key on real elements instead.

What it means

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.

Source

Thrown at packages/weex-template-compiler/build.js:1628

  if (l) {
    var attrs = el.attrs = new Array(l);
    for (var i = 0; i < l; i++) {
      attrs[i] = {
        name: el.attrsList[i].name,
        value: JSON.stringify(el.attrsList[i].value)
      };
    }
  } else if (!el.pre) {
    // non root node in pre blocks with no attributes
    el.plain = true;
  }
}

function processKey (el) {
  var exp = getBindingAttr(el, 'key');
  if (exp) {
    if (process.env.NODE_ENV !== 'production' && el.tag === 'template') {
      warn("<template> cannot be keyed. Place the key on real elements instead.");
    }
    el.key = exp;
  }
}

function processRef (el) {
  var ref = getBindingAttr(el, 'ref');
  if (ref) {
    el.ref = ref;
    el.refInFor = checkInFor(el);
  }
}

function processFor (el) {
  var exp;
  if ((exp = getAndRemoveAttr(el, 'v-for'))) {
    var inMatch = exp.match(forAliasRE);
    if (!inMatch) {

View on GitHub (pinned to 6c5d78ee04)

Solutions

  1. Move the :key binding from <template> to the real root element(s) inside it
  2. If children have no single root, wrap them in a keyed real element
  3. Upgrade consideration: Vue 3 allows keys on template v-for, so this warning is Vue 2-specific

Example fix

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

Strategy: validation

Validate before calling

function keyOnTemplate(template) {
  return /<template[^>]*\s(?::key|v-bind:key)\s*=/.test(template)
    ? 'key found on <template>; move it to real elements'
    : null;
}

Type guard

function hasNoTemplateKey(template) {
  return typeof template === 'string' && !/<template[^>]*\s(?::key|v-bind:key|key)\s*=/.test(template);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


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