quasarframework/quasar · error · Error
${message} at line ${lineNo} col ${colNo} (unclosed comment/
Error message
${message} at line ${lineNo} col ${colNo} (unclosed comment/unclosed string/unclosed tag) What it means
Quasar's HTML template preprocessor parses the index.html template into an AST; when the htmlparser2 tokenizer fails it reports the failure as a generic parse error annotated with the line and column plus the likely causes (unclosed comment, unclosed string, unclosed tag). throwParseError also prints the offending source line with a caret for context.
Source
Thrown at app-vite/lib/utils/template.js:44
function throwParseError(message, str, index) {
const whitespace = str.slice(0, index).split(newlineRE)
const lineNo = whitespace.length
const colNo = whitespace[lineNo - 1].length + 1
message +=
' at line ' +
lineNo +
' col ' +
colNo +
':\n\n' +
' ' +
str.split(newlineRE)[lineNo - 1] +
'\n' +
' '.repeat(colNo + 1) +
'^'
throw new Error(message)
}
function escapeRegExp(str) {
// From MDN
return str.replace(escapeRegexpRE, String.raw`\$&`) // $& means the whole matched string
}
function trimWS(str, wsLeft, wsRight) {
// Slightly confusing,
// but _}} will trim the left side of the following string
const leftTrim = wsLeft || wsLeft === false ? wsLeft : 'nl'
const rightTrim = wsRight || wsRight === false ? wsRight : false
if (!rightTrim && !leftTrim) return str
if (leftTrim === 'slurp' && rightTrim === 'slurp') {
return str.trim()
}View on GitHub (pinned to 4841521b5f)
Solutions
- Open the file and go to the reported line/column; fix the unclosed comment, quote or tag
- Look one or two lines above the caret — the actual mistake often starts earlier
- Validate the template with an HTML validator or by opening it in a browser's devtools parser
- Check for leftover Git conflict markers (<<<<<<<, =======) in index.html
Example fix
// before (index.html) <!-- build configuration <title>App</title> // after <!-- build configuration --> <title>App</title>
Defensive patterns
Strategy: try-catch
Validate before calling
// lightweight sanity check before build-time template parsing
const html = fs.readFileSync('index.html', 'utf8')
if ((html.match(/<!--/g) || []).length !== (html.match(/-->/g) || []).length) {
throw new Error('index.html has an unclosed HTML comment')
} Try / catch
try {
const ast = getAST(templateHtml)
} catch (err) {
if (err.message.includes('unclosed comment/unclosed string/unclosed tag')) {
console.error(err.message) // includes line/col + caret context
process.exit(1)
} else throw err
} Prevention
- Never leave TODO comments unterminated in index.html
- Validate the template after every manual edit or merge
- Watch for plugins/injections writing raw '<' into the template
- Run an HTML validator in CI on the source template
When it happens
Trigger: An index.html (or custom app template) passed to getAST contains malformed markup: an unterminated <!-- comment, an attribute string never closed, or a tag missing its closing '>' / matching end tag.
Common situations: Hand-editing index.html and leaving '<!-- TODO' open; a copy/paste that dropped a closing quote in an attribute; a build-time template injection inserting raw '<' into the head; merge conflicts leaving stray conflict markers in the template.
AI-assisted analysis of quasarframework/quasar@4841521b5f (2026-08-30).
Data as JSON: /api/errors/5090745f8dac2082.
Report an issue: GitHub.