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

create-quasar's template.js parses scaffolding templates into an AST. When the EJS-style parser cannot close a comment, string, or tag before end-of-file, throwParseError builds a message showing the offending source line with a caret pointer and throws. It means a template asset inside create-quasar is malformed, not your project files.

Source

Thrown at create-quasar/lib/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

  1. Open the file/line/column named in the error message and fix the unclosed comment, string or tag (add the closing '%>', quote or comment terminator)
  2. Check for leftover Git merge-conflict markers in the template file
  3. If you didn't edit templates, reinstall create-quasar (npm i -g create-quasar@latest) to replace corrupted template assets
  4. Run the failing command again to confirm parsing succeeds

Example fix

// before (template.js asset)
<div class="<%= props.name
// after
<div class="<%= props.name %>"></div>
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require('fs')
function looksBalanced(tpl) {
  return (tpl.match(/<%/g) || []).length === (tpl.match(/%>/g) || []).length
}
// check before processing: if (!looksBalanced(fs.readFileSync(file, 'utf8'))) fix file first

Type guard

function isClosedTag(tpl) {
  return typeof tpl === 'string' && (tpl.match(/<%/g) || []).length === (tpl.match(/%>/g) || []).length
}

Try / catch

try {
  const ast = getAST(tplPath)
} catch (err) {
  if (err.message.includes('unclosed')) {
    console.error(`Malformed template at ${err.message}; restore or fix the template file`)
  }
  throw err
}

Prevention

When it happens

Trigger: getAST encounters a template file containing an unterminated tag/comment/string literal — e.g. a template edited by hand where a closing '%>' or quote was dropped, or a line/comment opened at the end of the file.

Common situations: Developers customizing create-quasar's built-in templates (in template/ folders) accidentally break a tag; merge conflicts leaving conflict markers inside a template; editing templates with an editor that mangles quotes; contributing a new template with unbalanced syntax.

Related errors


AI-assisted analysis of quasarframework/quasar@4841521b5f (2026-08-30). Data as JSON: /api/errors/413df714fe4fddf8. Report an issue: GitHub.