toon-format/toon · error · ToonDecodeError

Expected ${expected} ${itemType}, but got ${actual}

Error message

Expected ${expected} ${itemType}, but got ${actual}

What it means

This ToonDecodeError is thrown by assertExpectedCount when strict-mode decoding encounters an array whose declared length in the header does not match the actual number of items decoded. TOON headers declare item counts (e.g. `items[3]{id}`), and the decoder trusts and verifies them; in strict mode any mismatch aborts the decode. It only fires when options.strict is true.

Source

Thrown at packages/toon/src/decode/validation.ts:16

import type { ArrayHeaderInfo, BlankLineInfo, Delimiter, Depth, ParsedLine } from '../types.ts'
import { COLON, LIST_ITEM_PREFIX } from '../constants.ts'
import { findUnquotedChar } from '../shared/string-utils.ts'
import { ToonDecodeError } from './errors.ts'

// #region Count and structure validation

export function assertExpectedCount(
  actual: number,
  expected: number,
  itemType: string,
  options: { strict: boolean },
  line: ParsedLine,
): void {
  if (options.strict && actual !== expected) {
    throw new ToonDecodeError(
      `Expected ${expected} ${itemType}, but got ${actual}`,
      { line: line.lineNumber, source: line.raw },
    )
  }
}

export function validateNoExtraListItems(
  nextLine: ParsedLine | undefined,
  itemDepth: Depth,
  expectedCount: number,
): void {
  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 },
    )
  }
}

View on GitHub (pinned to 604eac266e)

Solutions

  1. Count the actual items in the array body and correct the `[N]` in the header line to match
  2. Add or remove items so the body has exactly N items as declared
  3. Decode with { strict: false } to tolerate count mismatches (if count fidelity is acceptable)
  4. If data is programmatically generated, compute the header count from the same array you serialize

Example fix

// before
items[3]{id}
  1
  2
  3
  4
// after
items[4]{id}
  1
  2
  3
  4
Defensive patterns

Strategy: validation

Validate before calling

const declared = header.match(/\[(\d+)\]/)?.[1]
const actual = body.filter(l => isItem(l)).length
if (Number(declared) !== actual) throw new Error(`header says ${declared}, body has ${actual}`)

Type guard

function countsMatch(headerCount: number, items: unknown[]): boolean { return items.length === headerCount }

Try / catch

try { decode(input, { strict: true }) } catch (e) { if (e instanceof ToonDecodeError && /but got \d+$/.test(e.message)) console.error('count mismatch at line', e.line?.lineNumber, e.line?.source) }

Prevention

When it happens

Trigger: Calling decode with strict:true (the default) on any TOON array — primitive array (decodeInlinePrimitiveArray), keyed object, tabular array (decodeTabularArray), or list array (decodeListArray) — where the header count `[N]` differs from the number of items present in the body.

Common situations: Hand-edited TOON files where rows were added/removed without updating the `[N]` header; truncated or concatenated payloads; generator code that updates data but forgets to update the count; LLM output that miscounts items.

Related errors


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