toon-format/toon · error · ToonDecodeError
Expected ${header.length} tabular rows, but found more
Error message
Expected ${header.length} tabular rows, but found more What it means
Thrown by validateNoExtraTabularRows when a tabular array (header like `items[N]{a,b}`) contains more data rows at row depth than the declared count N: the following line is at row depth, is not a list bullet, and is classified as a data row (isDataRow). This stops the decoder from silently consuming rows that belong to another structure or were added without updating the header.
Source
Thrown at packages/toon/src/decode/validation.ts:46
if (nextLine?.depth === itemDepth && nextLine.content.startsWith(LIST_ITEM_PREFIX)) {
throw new ToonDecodeError(
`Expected ${expectedCount} list-form items, but found more`,
{ line: nextLine.lineNumber, source: nextLine.raw },
)
}
}
export function validateNoExtraTabularRows(
nextLine: ParsedLine | undefined,
rowDepth: Depth,
header: ArrayHeaderInfo,
): void {
if (
nextLine?.depth === rowDepth
&& !nextLine.content.startsWith(LIST_ITEM_PREFIX)
&& isDataRow(nextLine.content, header.delimiter)
) {
throw new ToonDecodeError(
`Expected ${header.length} tabular rows, but found more`,
{ line: nextLine.lineNumber, source: nextLine.raw },
)
}
}
export function validateNoBlankLinesInRange(
startLine: number,
endLine: number,
blankLines: BlankLineInfo[],
strict: boolean,
context: string,
): void {
if (!strict)
return
const firstBlank = blankLines.find(
blank => blank.lineNumber > startLine && blank.lineNumber < endLine,View on GitHub (pinned to 604eac266e)
Solutions
- Remove the extra rows so the body matches header.length
- Update the [N] header count to the actual row count
- Check the extra line — it may be a following key-value block misindented to row depth; fix its indentation instead
Example fix
// before
users[2]{id,name}
1,Alice
2,Bob
3,Carol
// after
users[3]{id,name}
1,Alice
2,Bob
3,Carol Defensive patterns
Strategy: validation
Validate before calling
const rows = block.slice(1).filter(l => !l.startsWith('- '))
if (rows.length !== headerCount) throw new Error(`tabular block has ${rows.length} rows, header declares ${headerCount}`) Type guard
function tabularRowCountsMatch(headerCount: number, rows: string[]): boolean { return rows.length === headerCount } Try / catch
try { decode(input) } catch (e) { if (e instanceof ToonDecodeError && e.message.includes('tabular rows, but found more')) console.error('extra row near line', e.line?.lineNumber, e.line?.source) } Prevention
- Keep tabular row generation and header count in the same code path
- Check indentation of lines after the array — the 'extra row' may be a misindented key-value pair
- Lint TOON payloads before decoding external input
When it happens
Trigger: Decoding a tabular array (decodeTabularArray) where the number of pipe/delimiter-separated rows at row depth exceeds header.length.
Common situations: Spreadsheet exports with rows appended after the count was computed; merging two row blocks; hand-editing a row but not the `[N]` header; a line that looks like a data row (delimiter before any unquoted colon) accidentally placed inside the array block.
Related errors
- Expected ${expected} ${itemType}, but got ${actual}
- Expected ${expectedCount} list-form items, but found more
- Unexpected indentation inside keyed tabular object
- Expected entry row inside keyed tabular object
- Blank lines inside ${context} are not allowed in strict mode
AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31).
Data as JSON: /api/errors/e3123a69584a70cc.
Report an issue: GitHub.