Meituan-Dianping/mpvue · warning
Unknown custom element: <${tag}> - did you register the comp
Error message
Unknown custom element: <${tag}> - did you register the component correctly? For recursive components, make sure to provide the "name" option. What it means
During patching, Vue encountered an element tag that is not a registered component, not a reserved HTML element, and not in `ignoredElements`, so `config.isUnknownElement(tag)` returns true. The element renders as a plain unknown custom element (behaves like a generic inline element with no component logic).
Source
Thrown at src/core/vdom/patch.js:129
if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
return
}
const data = vnode.data
const children = vnode.children
const tag = vnode.tag
if (isDef(tag)) {
if (process.env.NODE_ENV !== 'production') {
if (data && data.pre) {
inPre++
}
if (
!inPre &&
!vnode.ns &&
!(config.ignoredElements.length && config.ignoredElements.indexOf(tag) > -1) &&
config.isUnknownElement(tag)
) {
warn(
'Unknown custom element: <' + tag + '> - did you ' +
'register the component correctly? For recursive components, ' +
'make sure to provide the "name" option.',
vnode.context
)
}
}
vnode.elm = vnode.ns
? nodeOps.createElementNS(vnode.ns, tag)
: nodeOps.createElement(tag, vnode)
setScope(vnode)
/* istanbul ignore if */
if (__WEEX__) {
// in Weex, the default insertion order is parent-first.
// List items can be optimized to use children-first insertion
// with append="tree".
const appendAsTree = isDef(data) && isTrue(data.appendAsTree)View on GitHub (pinned to 6c5d78ee04)
Solutions
- Register the component globally (`Vue.component('my-widget', MyWidget)`) or locally in the parent's `components` option
- Give recursive components a `name` option matching the tag
- Match the tag casing exactly (kebab-case in DOM templates, PascalCase allowed in SFC templates)
- If it's a native/Web Component, add it to `Vue.config.ignoredElements = [/^my-/]`
Example fix
// before
<template><my-widget /></template>
// after
import MyWidget from './MyWidget.vue'
export default {
components: { MyWidget },
template: '<my-widget />'
} Defensive patterns
Strategy: validation
Validate before calling
function ensureRegistered (Vue, names) {
names.forEach(name => {
if (!Vue.options.components[name]) {
throw new Error('Component not registered: ' + name)
}
})
} Type guard
function isKnownTag (tag, components, reserved) {
return Object.prototype.hasOwnProperty.call(components, tag) || reserved.includes(tag)
} Prevention
- Register components locally in the parent's components option
- Give recursive components a name option
- Match kebab-case vs PascalCase per template style
- Add third-party/native custom elements to Vue.config.ignoredElements
When it happens
Trigger: Using `<my-widget>` in a template without `Vue.component('my-widget', ...)` or a local `components: { 'my-widget': ... }` registration; recursive component without a `name` option; unregistered kebab/case-mismatched component names; native Web Components not listed in `ignoredElements`.
Common situations: Case mismatch (`MyComponent` used as `<my-component>` without registration); forgetting `components: {}` local registration in SFC-less setups; upgrading from global registration to module-scoped components; using custom elements from other frameworks without configuring `Vue.config.ignoredElements`.
Related errors
- tag <${tag}> has no matching end tag.
- Templates should only be responsible for mapping the state t
- <template> cannot be keyed. Place the key on real elements i
- Invalid v-for expression: ${exp}
- v-${el.elseif ? ('else-if="' + el.elseif + '"') : 'else'} us
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/e54f130a3cc63846.
Report an issue: GitHub.