toon-format/toon · error · SyntaxError

Unterminated string: missing closing quote

Error message

Unterminated string: missing closing quote

What it means

A primitive token in the TOON input started with a double quote, indicating a quoted string, but findClosingQuote could not locate an unescaped closing quote before end-of-token. The parser throws SyntaxError rather than treating the rest of the line as string content, since the token boundaries are ambiguous.

Solutions

  1. Add the missing closing quote to the string token, e.g. `name: "hello"`
  2. Check for unescaped inner quotes — escape them as `\"` so the parser doesn't end the string early
  3. Avoid manual quoting: emit values via toon.encode which quotes/escapes correctly
  4. Check the file wasn't truncated mid-line (inspect the end of the file/line)

Example fix

// before
greeting: "hello
// after
greeting: "hello"
Defensive patterns

Strategy: try-catch

Validate before calling

function linesHaveClosedQuotes(text) {
  return text.split('\n').every(line => {
    let n = 0, esc = false
    for (const ch of line) {
      if (esc) { esc = false; continue }
      if (ch === '\\') { esc = true; continue }
      if (ch === '"') n++
    }
    return n % 2 === 0
  })
}

Try / catch

try {
  const value = toon.decode(text)
} catch (err) {
  if (err instanceof SyntaxError && err.message === 'Unterminated string: missing closing quote') {
    // point at the offending line; fix quoting before retry
  } else throw err
}

Prevention

When it happens

Trigger: Decoding TOON text containing an opening `"` with no closing `"` on the same token/line — e.g. `name: "hello` or an array row cell `"unterminated,x`. Reached via parseStringLiteral from parsePrimitiveToken, parseArrayHeaderLine, or parseFieldEntries.

Common situations: Hand-written TOON where the closing quote was forgotten; text containing characters that were escaped incorrectly so an escaped quote `\"` accidentally consumed the real closing quote; files truncated mid-line; content pasted from sources that strip trailing quotes.

Related errors


AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31). Data as JSON: /api/errors/66a4c1207c54628a. Report an issue: GitHub.

Appendix: source

Thrown at packages/toon/src/decode/parser.ts:475

      return null
  }

  if (isNumericLiteral(trimmedToken)) {
    const parsedNumber = Number.parseFloat(trimmedToken)
    return Object.is(parsedNumber, -0) ? 0 : parsedNumber
  }

  return trimmedToken
}

export function parseStringLiteral(token: string): string {
  const trimmedToken = trimSpaces(token)

  if (trimmedToken.startsWith(DOUBLE_QUOTE)) {
    const closingQuoteIndex = findClosingQuote(trimmedToken, 0)

    if (closingQuoteIndex === -1) {
      throw new SyntaxError('Unterminated string: missing closing quote')
    }

    if (closingQuoteIndex !== trimmedToken.length - 1) {
      throw new SyntaxError('Unexpected characters after closing quote')
    }

    const content = trimmedToken.slice(1, closingQuoteIndex)
    return unescapeString(content)
  }

  return trimmedToken
}

export function parseUnquotedKey(content: string, start: number): { key: string, end: number } {
  // A raw scan would cut `a "b:c" d: 1` at the quoted colon and split the key in two.
  const colonIndex = findUnquotedChar(content, COLON, start)

  if (colonIndex === -1) {

View on GitHub (pinned to 604eac266e)