toon-format/toon · error · ToonDecodeError

Indentation depth jump: expected depth ${parentDepth + 1}, b

Error message

Indentation depth jump: expected depth ${parentDepth + 1}, but found ${firstNestedLine.depth}

What it means

In strict mode, nested content may only indent exactly one level deeper than its parent. assertNoDepthJump throws when the first nested line under a key skips levels (e.g. parent at depth 0, child at depth 2), which would be ambiguous indentation in TOON. Non-strict mode tolerates the jump.

Source

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

      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 {
  if (strict && firstNestedLine.depth > parentDepth + 1) {
    throw new ToonDecodeError(
      `Indentation depth jump: expected depth ${parentDepth + 1}, but found ${firstNestedLine.depth}`,
      { line: firstNestedLine.lineNumber, source: firstNestedLine.raw },
    )
  }
}

function overIndentedLineError(line: ParsedLine, expectedDepth: Depth): ToonDecodeError {
  return new ToonDecodeError(
    `Over-indented line: expected depth ${expectedDepth}, but found ${line.depth}`,
    { line: line.lineNumber, source: line.raw },
  )
}

// Both modes reject a bare token outside root primitive position, so it must not reach
// the non-strict paths that drop an over-indented line.
function assertNotScalarLine(line: ParsedLine): void {
  const isListItem = line.content.startsWith(LIST_ITEM_PREFIX) || line.content === LIST_ITEM_MARKER
  if (isListItem || findUnquotedChar(line.content, COLON) !== -1) {

View on GitHub (pinned to 604eac266e)

Solutions

  1. Re-indent the nested block so each level steps by exactly one depth unit
  2. Decode with strict:false if lenient parsing is acceptable
  3. Normalize indentation with a formatter/linter before decoding
  4. Replace tabs with a consistent space count

Example fix

// before (depth jump 0 -> 2)
user:
    name: Ada

// after
user:
  name: Ada
Defensive patterns

Strategy: validation

Validate before calling

function hasUniformIndentStep(text: string, maxStep = 1): boolean {
  const depths = text.split('\n')
    .filter(l => l.trim())
    .map(l => Math.floor((l.match(/^ */) ?? [''])[0].length / 2))
  return depths.every((d, i) => i === 0 || d - depths[i - 1] <= maxStep)
}

Try / catch

try {
  return decode(input, { strict: true })
} catch (e) {
  if (e instanceof ToonDecodeError && e.message.includes('Indentation depth jump')) {
    return decode(normalizeIndentation(input), { strict: true })
  }
  throw e
}

Prevention

When it happens

Trigger: decodeKeyValue encountering a nested block whose first line's depth exceeds parentDepth+1 while options.strict is true — typically input indented with inconsistent step sizes or mixed tab/space expansion.

Common situations: Editing TOON by hand and adding an extra indent level; converting YAML with 4-space indents into TOON where only 2-space steps are expected after normalization; copy-paste that re-indents a block.

Related errors


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