evanw/esbuild · error · LexerPanic

Unterminated string literal

Error message

Unterminated string literal

What it means

This is a JavaScript/TypeScript lexer error indicating that a string literal (single-quote, double-quote, or template literal) was not properly terminated before the lexer reached the end of file (code point -1) or, for non-template strings, a bare newline character. The error is added as a RangeError and the lexer panics with LexerPanic to abort parsing.

Source

Thrown at internal/js_lexer/js_lexer.go:1483

		stringLiteral:
			for {
				switch lexer.codePoint {
				case '\\':
					needsSlowPath = true
					lexer.step()

					// Handle Windows CRLF
					if lexer.codePoint == '\r' && lexer.json != JSON {
						lexer.step()
						if lexer.codePoint == '\n' {
							lexer.step()
						}
						continue
					}

				case -1: // This indicates the end of the file
					lexer.addRangeError(logger.Range{Loc: logger.Loc{Start: int32(lexer.end)}}, "Unterminated string literal")
					panic(LexerPanic{})

				case '\r':
					if quote != '`' {
						lexer.addRangeError(logger.Range{Loc: logger.Loc{Start: int32(lexer.end)}}, "Unterminated string literal")
						panic(LexerPanic{})
					}

					// Template literals require newline normalization
					needsSlowPath = true

				case '\n':
					if quote != '`' {
						lexer.addRangeError(logger.Range{Loc: logger.Loc{Start: int32(lexer.end)}}, "Unterminated string literal")
						panic(LexerPanic{})
					}

				case '$':
					if quote == '`' {

View on GitHub (pinned to f6058f8364)

Solutions

  1. Add the missing closing quote character (' or " or `) to terminate the string
  2. For multi-line strings, use a backtick template literal or concatenate with '+'
  3. Check for stray newline characters inside the string by examining the source around the error location
  4. If the file appears truncated, verify the file is complete and not cut off

Example fix

// before
const greeting = "hello world;
// after
const greeting = "hello world";
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate source files for unterminated string literals
function checkUnterminatedStrings(source) {
  for (let i = 0; i < source.length; i++) {
    const ch = source[i]
    if (ch === '"' || ch === "'") {
      // scan forward for closing quote
      let j = i + 1
      while (j < source.length && source[j] !== ch) {
        if (source[j] === '\\') j++ // skip escaped char
        if (source[j] === '\n' || source[j] === '\r') {
          return { unterminated: true, line: source.substring(0, i).split('\n').length }
        }
        j++
      }
      if (j >= source.length) {
        return { unterminated: true, line: source.substring(0, i).split('\n').length }
      }
      i = j
    }
  }
  return { unterminated: false }
}

Try / catch

try {
  const result = await esbuild.transform(source, { loader: 'ts' })
} catch (e) {
  if (e.message?.includes('Unterminated string literal')) {
    const loc = e.errors?.[0]?.location
    console.error(`Syntax error at ${loc?.file}:${loc?.line}:${loc?.column}: add the missing quote`)
  }
  throw e
}

Prevention

When it happens

Trigger: A source file contains an unclosed string literal such as const x = "hello at the end of the file without a closing quote, or a single/double-quoted string that contains a raw newline character (not allowed in JS/TS).

Common situations: Missing closing quote due to a typo, a string accidentally spanning a newline in non-template-literal context, an escaped character that was meant to include the closing quote, or corrupted/truncated source files.

Related errors


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/609f482084ebcd29. Report an issue: GitHub.