build-a-json-parser / lesson-23.md
Lesson 23 · Errors and limits

A depth guard

Recursive descent recurses as deep as the input nests, so a pathologically nested document could exhaust the stack. Today you add a configurable depth limit that rejects over-deep nesting with a clear error instead of crashing.

The goal

Reject nesting beyond a configurable maximum depth with a positioned error.

Start here - the target
TO DO
Scenario: Nesting past the limit
Givena maximum nesting depth of 3
Whenthe input is parsed with that limit
ThenParseWith("[[[1]]]", 3) succeeds with the nested Array value
AndParseWith("[[[[1]]]]", 3) gives "maximum nesting depth exceeded at line 1, column 4"
Background

Because parseValue calls itself for every nested container, a document like a thousand stacked brackets would recurse a thousand frames deep and could overflow the call stack - a classic denial-of-service against naive parsers. The defense is a depth guard: count how many containers are currently open, and refuse to go deeper than a configured maximum, reporting a clean error rather than letting the runtime crash.

Thread a depth counter through the array and object parsers: increment when entering a container, check it against the limit, and decrement on the way out. When the limit is exceeded, produce a ParseError at the bracket or brace that crossed the line. Expose the cap through a ParseWith(input, maxDepth) entry point and have the plain Parse call it with a sensible default like 128. Pin the boundary exactly: nesting right at the limit still parses, and one level past it is the error. That completes the parser - it now accepts every valid document and rejects every invalid one with a precise, safe message.

Make it work
// thread a depth counter through the container parsers:
// entering an array or object: depth++
// if depth > maxDepth: ParseError at the opening bracket/brace
// leaving it: depth--
// Parse(input) calls ParseWith(input, 128); ParseWith exposes the cap
CheckpointDONE
Over-deep nesting is rejected with a clear error. Commit and stop here.