toon-format/toon · error · SyntaxError

Unmatched brace in field list

Error message

Unmatched brace in field list

What it means

A nested field group's opening brace `{` in a field-list entry had no matching closing `}` (findMatchingBrace returned -1). TOON nested field syntax must be balanced, so an unclosed group makes the header unparseable and the parser throws SyntaxError.

Source

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

  return entries.map((entry) => {
    const trimmedEntry = trimSpaces(entry)
    if (!trimmedEntry) {
      throw new SyntaxError('Empty field name in field list')
    }

    const groupStart = findUnquotedChar(trimmedEntry, OPEN_BRACE)
    if (groupStart === -1) {
      return { name: parseStringLiteral(trimmedEntry) }
    }

    const namePart = trimSpaces(trimmedEntry.slice(0, groupStart))
    if (!namePart) {
      throw new SyntaxError('Missing field name before nested field group')
    }

    const groupEnd = findMatchingBrace(trimmedEntry, groupStart)
    if (groupEnd === -1) {
      throw new SyntaxError('Unmatched brace in field list')
    }
    if (groupEnd !== trimmedEntry.length - 1) {
      throw new SyntaxError('Unexpected content after nested field group')
    }

    const children = parseFieldEntries(trimmedEntry.slice(groupStart + 1, groupEnd), delimiter)
    return { name: parseStringLiteral(namePart), children }
  })
}

/**
 * Splits a field list on the active delimiter at brace depth zero,
 * respecting quoted names and escape sequences.
 */
function splitFieldEntries(content: string, delimiter: Delimiter): string[] {
  const entries: string[] = []
  let entryBuffer = ''
  let inQuotes = false

View on GitHub (pinned to 604eac266e)

Solutions

  1. Add the missing closing `}` so the nested group is balanced, e.g. `user{name,age}`
  2. Count braces in the header line to verify balance before decoding
  3. Fix the generator/template so each `{` emits its matching `}`
  4. Round-trip a known-good document through toon.encode to compare header syntax

Example fix

// before
users[2]{user{name,age}:
// after
users[2]{user{name,age}}:
Defensive patterns

Strategy: try-catch

Validate before calling

function bracesBalanced(headerLine) {
  let n = 0
  for (const ch of headerLine) {
    if (ch === '{') n++
    if (ch === '}') n--
    if (n < 0) return false
  }
  return n === 0
}

Try / catch

try {
  const value = toon.decode(text)
} catch (err) {
  if (err instanceof SyntaxError && err.message === 'Unmatched brace in field list') {
    // highlight header line; check brace balance before retry
  } else throw err
}

Prevention

When it happens

Trigger: Decoding input where a field-list entry contains `{` without a matching `}` — e.g. `users[2]{user{name,age}:` or `items[1]{a{b}:` — reached through parseFieldEntries from parseArrayHeaderLine.

Common situations: Hand-edited headers where a closing brace was deleted; truncated lines from copy-paste; template output that dropped the final `}` due to string formatting bugs.

Related errors


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