toon-format/toon · error · SyntaxError
Unexpected content after nested field group
Error message
Unexpected content after nested field group
What it means
A nested field group in a field-list entry was properly closed, but the closing `}` was not the last character of the trimmed entry — extra content followed it (e.g. `user{name}extra`). TOON requires the group to terminate the entry, so trailing content is rejected to avoid silently misparsing.
Source
Thrown at packages/toon/src/decode/parser.ts:242
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
let braceDepth = 0
let i = 0
View on GitHub (pinned to 604eac266e)
Solutions
- Move any sibling fields after the group into a separate delimiter-separated entry, e.g. `{user{name},age}` not `{user{name}age}`
- Remove stray characters after the closing `}`
- Fix the generator so nested groups are always the last part of their entry
- Compare against output from toon.encode for correct field-list ordering
Example fix
// before
users[2]{user{name}age}:
// after
users[2]{user{name},age}: Defensive patterns
Strategy: try-catch
Validate before calling
function noContentAfterGroups(toonText) {
const m = toonText.match(/\[\d+\]\{(.*)\}\s*:$/m)
if (!m) return true
return !/\}[^,;}]/.test(m[1])
} Try / catch
try {
const value = toon.decode(text)
} catch (err) {
if (err instanceof SyntaxError && err.message.includes('after nested field group')) {
// move trailing text into its own delimiter-separated entry
} else throw err
} Prevention
- A nested group must end its entry; put siblings after a delimiter, never after the }
- Generate headers with toon.encode rather than string templates
- Diff hand-edited headers against encoder output
When it happens
Trigger: Decoding a field list where text follows a nested group's closing brace, like `items[2]{user{name}x,age}:` — parseFieldEntries checks groupEnd !== trimmedEntry.length - 1 and throws. Reached via parseArrayHeaderLine.
Common situations: Hand-edited headers appending delimiters or text after a nested group instead of before it; generators that concatenate fields in the wrong order (group first, then siblings inside the same entry instead of after the comma).
Related errors
- Missing field name before nested field group
- Unmatched brace in field list
- Invalid array length: "${seg}" (expected non-negative intege
- Empty field name in field list
- Expected list item to start with "${LIST_ITEM_PREFIX}"
AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31).
Data as JSON: /api/errors/35151d53987a77b0.
Report an issue: GitHub.