llama.cpp b11871 now rejects excessively nested JSON requests before processing them. Developers running servers can reduce shutdowns caused by a single faulty request. Requests exceeding the depth limit receive HTTP 400.

1. Why recursion stopped the server

The problem arose during recursive processing, which repeatedly calls the same function while traversing the structure after reading JSON. If this exhausts the stack memory used to handle HTTP requests, the entire server can shut down.

According to the release notes, tool schema requests defining input formats caused server shutdowns at a few hundred levels on macOS and around 10000 levels on Linux.

The following reproduction code from the pull request (PR) sends a tool definition with a depth of 1000. It can shut down the old server. It did so on macOS; the PR says to raise the depth to 30000 on Linux.

llama-server -hf LiquidAI/LFM2.5-VL-450M-GGUF -hff LFM2.5-VL-450M-F16.gguf --port 8080 &
python3 -c "d=1000; s='{\"type\": \"array\", \"items\": '*d+'{\"type\": \"string\"}'+'}'*d; print('{\"messages\": [{\"role\": \"user\", \"content\": \"hi\"}], \"max_tokens\": 1, \"tools\": [{\"type\": \"function\", \"function\": {\"name\": \"f\", \"description\": \"d\", \"parameters\": {\"type\": \"object\", \"properties\": {\"x\": '+s+'}}}}]}')" > deep.json
curl -s localhost:8080/v1/chat/completions -H 'Content-Type: application/json' --data-binary @deep.json

2. Rejecting requests deeper than 128 levels before processing

The change checks the depth of parsed JSON, whose text has been read into a structure, to prevent excessive recursion afterward. According to the PR implementation notes, the check function itself is limited to 129 recursive calls.

The release notes say inputs deeper than 128 levels receive HTTP 400. Instead of checking whether the server has shut down, callers can receive a response indicating that an excessively deep request was rejected.

Checks cover chat request tool definitions, tool call arguments (values passed to tools), template variables (values inserted into templates), and schemas. Completion request schemas and entire state management request bodies are also checked. Excessively deep gemma4 tool results remain text rather than being interpreted as structured results.

This blocks paths where deep inputs exhaust the server stack while preserving normal request flows. However, JSON deeper than 128 levels is no longer processed, so callers relying on that depth must simplify their request structures.

3. Response differences between the original and patched code

Below are the PR author’s comparisons of the original and patched code on macOS M3 Ultra. 200 means success; 400 means rejection for excessive depth. The patched code returned 400 from 130 levels in the measured request types.

Table: HTTP responses by nesting depth

Conditions: macOS M3 Ultra, comparing the original and patched code in the PR. State management uses d1-omni; tool call arguments use string inputs.

Unit: HTTP status code. — means no response because the server shut down.

Response differences between the original and patched code
Nesting depthOriginal: state managementOriginal: tool parametersOriginal: response formatOriginal: tool call argumentsPatched: all
100200200200200200
120200200200200200
130200200200200400
700500——200400
1000500——200400
2000————400
10000————400
30000————400
1000000————400

At 100 and 120 levels, the original code returned the same responses as the patched code. The 500 responses for state management requests at 700 and 1000 levels were batch size errors, not server shutdowns.

The PR adds that on Linux, original schema requests caused shutdowns from 10000 levels, and state and argument requests from 30000 levels. The patched code returned 400 from 130 levels.

4. Check overhead and remaining scope

The PR author measured check overhead on M3 Max. A 0.33MB chat request took 0.02ms to check versus 1.4ms to parse as JSON. A 10MB request took 0.54ms (parsing: 35ms). An array of 1000000 integers took 3.8ms (parsing: 41ms). These are measurements from the PR’s environment. Check time increases with input size, but was shorter than parsing time in all three reported cases.

The PR notes that some templates on macOS can exhaust the stack even below 128 levels. It also excludes recursion issues in prefills and JSON schema conversion caused by factors other than nesting. Prefills are text placed before the model response in requests ending with an assistant message.

The key benefit of b11871 is reducing operational burden by turning deep-input failures from whole-server shutdowns into request-level rejections.