{"record":{"id":"aa5bea1c131fea82","repo":"toon-format/toon","slug":"missing-field-name-before-nested-field-group","errorCode":null,"errorMessage":"Missing field name before nested field group","messagePattern":"Missing field name before nested field group","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/toon/src/decode/parser.ts","lineNumber":234,"sourceCode":" * after a nested group's closing brace; callers decide strict fallthrough.\n */\nexport function parseFieldEntries(fieldsContent: string, delimiter: Delimiter): FieldNode[] {\n  const entries = splitFieldEntries(fieldsContent, delimiter)\n\n  return entries.map((entry) => {\n    const trimmedEntry = trimSpaces(entry)\n    if (!trimmedEntry) {\n      throw new SyntaxError('Empty field name in field list')\n    }\n\n    const groupStart = findUnquotedChar(trimmedEntry, OPEN_BRACE)\n    if (groupStart === -1) {\n      return { name: parseStringLiteral(trimmedEntry) }\n    }\n\n    const namePart = trimSpaces(trimmedEntry.slice(0, groupStart))\n    if (!namePart) {\n      throw new SyntaxError('Missing field name before nested field group')\n    }\n\n    const groupEnd = findMatchingBrace(trimmedEntry, groupStart)\n    if (groupEnd === -1) {\n      throw new SyntaxError('Unmatched brace in field list')\n    }\n    if (groupEnd !== trimmedEntry.length - 1) {\n      throw new SyntaxError('Unexpected content after nested field group')\n    }\n\n    const children = parseFieldEntries(trimmedEntry.slice(groupStart + 1, groupEnd), delimiter)\n    return { name: parseStringLiteral(namePart), children }\n  })\n}\n\n/**\n * Splits a field list on the active delimiter at brace depth zero,\n * respecting quoted names and escape sequences.","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/toon-format/toon/blob/604eac266e35166bed6f5b9e3bd586e9c60a9330/packages/toon/src/decode/parser.ts#L216-L252","documentation":"Inside a field list entry, a nested field group `{...}` was found (e.g. `{a,{b}}` without a name), but the text before the opening brace was empty after trimming. TOON nested field syntax requires a field name before the group, like `user{name,age}`, so nameless groups are rejected.","triggerScenarios":"Decoding a header field list containing a bare nested group with no preceding name — e.g. `items[2]{{name},age}:` or an entry like `,` followed by `{...}` — via parseFieldEntries when parsing parseArrayHeaderLine.","commonSituations":"Hand-writing nested TOON headers and forgetting the parent field name; generators that omit a name for nested object columns (e.g. unnamed object fields in source JSON); copy-paste errors deleting a name but leaving its group.","solutions":["Add the missing field name before the brace group, e.g. `user{name}` instead of `{name}`","If the source object has an unnamed key, rename it before encoding","Check every `{` in the field list has a non-empty name immediately before it","Fix the generator to emit `name{...}` for every nested group"],"exampleFix":"// before\nusers[2]{{name},age}:\n// after\nusers[2]{user{name},age}:","handlingStrategy":"try-catch","validationCode":"function hasUnnamedNestedGroups(toonText) {\n  const m = toonText.match(/\\[\\d+\\]\\{([^}]*)\\}/)\n  if (!m) return false\n  return /[{,;\\t]\\s*\\{/.test(`{${m[1]}}`) // brace group not preceded by a name\n}","typeGuard":null,"tryCatchPattern":"try {\n  const value = toon.decode(text)\n} catch (err) {\n  if (err instanceof SyntaxError && err.message === 'Missing field name before nested field group') {\n    // prompt to add the missing parent field name\n  } else throw err\n}","preventionTips":["Always write nested groups as name{...}, never a bare {...}","Rename empty/unnamed source keys before encoding","Learn the nested-fields header syntax from toon's docs before hand-writing"],"tags":["syntax","toon","nested-fields","parser"],"backgroundTag":"invalid-array-header","analyzedSha":"604eac266e35166bed6f5b9e3bd586e9c60a9330","analyzedAt":"2026-08-31T11:09:25.043Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}