Common causes
1. A block element inside a paragraph
A <p> cannot contain <div>, <ul>, <table> or headings. When the parser sees one, it closes the paragraph automatically, so your own </p> later has nothing to close. Use a <div> as the wrapper, or keep the block outside the paragraph.
<p>Order shipped.
<div class="actions">Track</div>
</p><div>
<p>Order shipped.</p>
<div class="actions">Track</div>
</div>2. A duplicate end tag left after editing
Deleting an element’s opening tag but not its closing tag, or pasting a fragment twice, leaves a stray end tag. Formatting the file makes the extra one stand out.
<ul>
<li>One</li>
</li>
</ul><ul>
<li>One</li>
</ul>3. Overlapping tags
Inline elements must close in reverse order. <b><i>…</b></i> closes b while i is still open.
<p><b><i>Important</b></i></p><p><b><i>Important</i></b></p>4. End tags on void elements
<br>, <img>, <input>, <hr> and <meta> never have content, so </br> or </img> is invalid. Write them without an end tag (a trailing /> is allowed but optional).
<p>Line one<br></br>Line two</p><p>Line one<br>Line two</p>Frequently asked questions
Why does the page render correctly in the browser?
The HTML parser is designed to recover from errors: it ignores stray end tags and closes elements implicitly. The rendered structure may still differ from what you intended, which matters for CSS selectors and scripts.
Which elements close a paragraph automatically?
Block-level elements such as div, ul, ol, table, form, pre, blockquote, section, article and h1–h6 all end an open p element. Inline elements such as span, a and strong do not.
Is this error the same in Vue and Angular templates?
Yes. Their compilers parse templates with HTML rules and report stray end tags (“Invalid end tag” in Vue) instead of silently fixing them, because a template has to produce a predictable structure.