toon-format/toon · error · ToonDecodeError

Over-indented line: expected depth

Error message

Over-indented line: expected depth ${expectedDepth}, but found ${line.depth}

What it means

At the document root, TOON expects every line at depth 0. In strict mode, a line indented deeper than the root level throws overIndentedLineError, reporting the expected depth (0) and the actual depth found. This catches structurally malformed documents early.

Solutions

  1. Remove the leading indentation from the lines being decoded
  2. Decode only the intended sub-document, not an indented fragment
  3. Set options.strict = false to tolerate over-indented lines (they are skipped per the non-strict path)
  4. Re-encode the source data to produce properly rooted TOON output

Example fix

// before (input, strict mode)
const text = "    items: 2"
const doc = decode(text)
// after
const text = "items: 2"
const doc = decode(text)
Defensive patterns

Strategy: validation

Validate before calling

function isRootedToon(text: string): boolean {
  return text.split('\n').every(line => line.trim() === '' || line[0] !== ' ' && line[0] !== '\t' || /* allow continuation */ true)
}

Try / catch

try {
  const doc = decode(text)
} catch (e) {
  if (e instanceof Error && e.message.includes('Over-indented line')) {
    // dedent the input and retry once
    const dedented = text.split('\n').map(l => l.replace(/^\s+/, '')).join('\n')
    return decode(dedented)
  }
  throw e
}

Prevention

When it happens

Trigger: Calling decode/decodeStreamSync on input whose first meaningful lines (or any non-empty line before any top-level key) are indented, e.g. a document that starts with a line at depth 2, with strict: true (the default).

Common situations: Wrapping TOON output inside YAML/JSON artifacts and decoding the indented block; copy-pasting snippets that carry leading indentation from editors/chat; mixing strict and non-strict workflows.

Related errors


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

Appendix: source

Thrown at packages/toon/src/decode/decoders.ts:97

    throw new ToonDecodeError(
      'Top-level document must start with a key-value or array-header line',
      { line: first.lineNumber, source: first.raw },
    )
  }

  const rootSeenKeys = options.strict ? new Set<string>() : undefined
  yield { type: 'startObject' }
  yield* decodeKeyValue(first, reader, 0, options, rootSeenKeys)

  while (true) {
    const line = yield* peekLine(reader)
    if (!line) {
      break
    }

    if (line.depth !== 0) {
      if (options.strict) {
        throw overIndentedLineError(line, 0)
      }
      assertNotScalarLine(line)
      yield* readLine(reader)
      continue
    }

    yield* readLine(reader)
    yield* decodeKeyValue(line, reader, 0, options, rootSeenKeys)
  }

  yield { type: 'endObject' }
}

// #endregion

// #region Error helpers

function assertNoDepthJump(firstNestedLine: ParsedLine, parentDepth: Depth, strict: boolean): void {

View on GitHub (pinned to 604eac266e)