Meituan-Dianping/mpvue · warning
tag <${tag}> has no matching end tag.
Error message
tag <${tag}> has no matching end tag. What it means
This dev-mode warning is emitted by the HTML parser's parseEndTag when a closing tag does not match any open element in the parser's element stack. The parser closes every remaining element above the mismatch point via options.end, and warns for each one left without a matching end tag. It indicates malformed template markup (unclosed or wrongly nested tags).
Source
Thrown at packages/weex-template-compiler/build.js:520
if (tagName) {
for (pos = stack.length - 1; pos >= 0; pos--) {
if (stack[pos].lowerCasedTag === lowerCasedTagName) {
break
}
}
} else {
// If no tag name is provided, clean shop
pos = 0;
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (var i = stack.length - 1; i >= pos; i--) {
if (process.env.NODE_ENV !== 'production' &&
(i > pos || !tagName) &&
options.warn
) {
options.warn(
("tag <" + (stack[i].tag) + "> has no matching end tag.")
);
}
if (options.end) {
options.end(stack[i].tag, start, end);
}
}
// Remove the open elements from the stack
stack.length = pos;
lastTag = pos && stack[pos - 1].tag;
} else if (lowerCasedTagName === 'br') {
if (options.start) {
options.start(tagName, [], true, start, end);
}
} else if (lowerCasedTagName === 'p') {
if (options.start) {
options.start(tagName, [], false, start, end);View on GitHub (pinned to 6c5d78ee04)
Solutions
- Add the missing end tag for the element named in the warning
- Reorder the end tags so nesting matches the start tags
- Validate the template HTML in an editor/linter before compiling
Example fix
// before <div><span>hi</div> // after <div><span>hi</span></div>
Defensive patterns
Strategy: validation
Validate before calling
function checkBalancedTags(template) {
const voidTags = new Set(['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr']);
const stack = [];
const re = /<\/?([a-zA-Z][\w-]*)[^>]*?(\/?)>/g;
let m;
while ((m = re.exec(template))) {
const [full, tag, selfClose] = m;
if (full.startsWith('</')) {
if (stack.pop() !== tag) return `mismatched end tag </${tag}>`;
} else if (!selfClose && !voidTags.has(tag.toLowerCase())) {
stack.push(tag);
}
}
return stack.length ? `unclosed tag <${stack[stack.length-1]}>` : null;
} Type guard
function isTemplateBalanced(template) {
return typeof template === 'string' && checkBalancedTags(template) === null;
} Prevention
- Run templates through an HTML linter (eslint-plugin-vue, HTMLHint) before compiling
- Keep templates small so nesting mistakes are easy to spot
- Use editor auto-close-tag features to avoid unclosed elements
When it happens
Trigger: Compiling a template where an element is never closed, or end tags appear out of nesting order, so parseEndTag finds no stack entry matching the closing tag name (warn fires when i > pos or tagName is empty and options.warn is set).
Common situations: Hand-written templates with <div> opened but not closed, self-closing a non-void tag incorrectly, or JSX-like nesting mistakes; often after copy-pasting markup or refactoring without closing a wrapper element.
Related errors
- 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
- text "${children[i].text.trim()}" between v-if and v-else(-i
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/d0ad1095c055bc78.
Report an issue: GitHub.