Description
Two related bugs in common/json-schema-to-grammar.cpp cause llama-server to reject an
otherwise-valid tool-calling request with Failed to initialize samplers: failed to parse grammar
(or number of repetitions exceeds sane defaults) when the request's tools array contains a
schema shape that's uncommon but fully valid JSON Schema. Because all tool schemas are compiled into
one combined GBNF grammar, a single bad schema in the array breaks the entire request — every tool
call fails, not just the offending one.
Both were hit in the wild via Claude Code's real tool set (which includes exactly these two shapes),
not a synthetic edge case.
Bug 1 — object schema with zero properties produces invalid GBNF
A schema like:
{"type": "object", "properties": {}}
(e.g. a "placeholder"/no-op tool with no parameters) causes _build_object_rule() to fall through
both the required_props and optional_props loops (both empty), then concatenate the object rule
as:
Two space tokens back-to-back with nothing between them — this is invalid GBNF and fails to parse:
tool-DeferredToolPlaceholder-schema ::= "{" space space "}"
E failed to parse grammar
Bug 2 — large maxLength produces a repetition count above the grammar engine's own sanity cap
A string schema like:
{"type": "string", "maxLength": 524288}
(a perfectly valid, if generous, maxLength) causes the minLength/maxLength branch to emit:
tool-Foo-schema-bar ::= "\"" char{0,524288} "\""
src/llama-grammar.cpp hard-caps any single repetition count at MAX_REPETITION_THRESHOLD (2000)
and throws:
parse: error parsing grammar: number of repetitions exceeds sane defaults, please reduce the number of repetitions
So a schema author who sets a large-but-reasonable maxLength (2^19 chars here, for a tool that
accepts an arbitrary script/document body) breaks grammar init entirely, with no partial/graceful
degradation.
Repro
Minimal repro against /v1/chat/completions (either bug reproduces independently):
# Bug 1
curl -s http://127.0.0.1:8095/v1/chat/completions -H 'Content-Type: application/json' -d '{
"model": "qwen3-30b",
"messages": [{"role":"user","content":"hi"}],
"tools": [{"type":"function","function":{"name":"Placeholder","parameters":{"type":"object","properties":{}}}}]
}'
# -> 400 "Failed to initialize samplers: failed to parse grammar"
# Bug 2
curl -s http://127.0.0.1:8095/v1/chat/completions -H 'Content-Type: application/json' -d '{
"model": "qwen3-30b",
"messages": [{"role":"user","content":"hi"}],
"tools": [{"type":"function","function":{"name":"Foo","parameters":{"type":"object","properties":{"bar":{"type":"string","maxLength":524288}},"required":["bar"]}}}]
}'
# -> 400 "number of repetitions exceeds sane defaults"
Both confirmed present as of 571d0d5 (2026-07-18).
Suggested fix
Patched locally in common/json-schema-to-grammar.cpp:
Bug 1 — in _build_object_rule(), short-circuit before the concatenation when both prop lists
are empty:
if (required_props.empty() && optional_props.empty()) {
return "\"{\" space \"}\"";
}
Bug 2 — in the minLength/maxLength string branch, clamp max_len to "unbounded" once it
exceeds the grammar engine's own repetition threshold, rather than passing the raw value through to
build_repetition():
constexpr int GRAMMAR_MAX_REPETITION_THRESHOLD = 2000; // mirrors llama-grammar.cpp's MAX_REPETITION_THRESHOLD
if (max_len > GRAMMAR_MAX_REPETITION_THRESHOLD) {
max_len = std::numeric_limits<int>::max();
}
This still respects minLength; it just stops trying to length-cap at the grammar level for values
the engine can't represent as a literal repetition count anyway (arguably the right behavior even
without the threshold bug, since a length this large isn't meaningfully enforceable via GBNF
repetition).
Both patches tested locally: rebuilt llama-server, verified the exact failing multi-tool request
(10 tools including both shapes above) now parses and returns a normal completion, with no change to
grammar behavior for schemas that don't hit either edge case.
Happy to open a PR with these two changes if useful — wanted to file the bug report first in case
there's a different intended approach (e.g. whether an oversized maxLength should instead be
rejected at the schema-validation layer with a clearer error, rather than silently uncapped).
Description
Two related bugs in
common/json-schema-to-grammar.cppcausellama-serverto reject anotherwise-valid tool-calling request with
Failed to initialize samplers: failed to parse grammar(or
number of repetitions exceeds sane defaults) when the request'stoolsarray contains aschema shape that's uncommon but fully valid JSON Schema. Because all tool schemas are compiled into
one combined GBNF grammar, a single bad schema in the array breaks the entire request — every tool
call fails, not just the offending one.
Both were hit in the wild via Claude Code's real tool set (which includes exactly these two shapes),
not a synthetic edge case.
Bug 1 — object schema with zero properties produces invalid GBNF
A schema like:
{"type": "object", "properties": {}}(e.g. a "placeholder"/no-op tool with no parameters) causes
_build_object_rule()to fall throughboth the
required_propsandoptional_propsloops (both empty), then concatenate the object ruleas:
Two
spacetokens back-to-back with nothing between them — this is invalid GBNF and fails to parse:Bug 2 — large
maxLengthproduces a repetition count above the grammar engine's own sanity capA string schema like:
{"type": "string", "maxLength": 524288}(a perfectly valid, if generous,
maxLength) causes theminLength/maxLengthbranch to emit:src/llama-grammar.cpphard-caps any single repetition count atMAX_REPETITION_THRESHOLD(2000)and throws:
So a schema author who sets a large-but-reasonable
maxLength(2^19 chars here, for a tool thataccepts an arbitrary script/document body) breaks grammar init entirely, with no partial/graceful
degradation.
Repro
Minimal repro against
/v1/chat/completions(either bug reproduces independently):Both confirmed present as of
571d0d5(2026-07-18).Suggested fix
Patched locally in
common/json-schema-to-grammar.cpp:Bug 1 — in
_build_object_rule(), short-circuit before the concatenation when both prop listsare empty:
Bug 2 — in the
minLength/maxLengthstring branch, clampmax_lento "unbounded" once itexceeds the grammar engine's own repetition threshold, rather than passing the raw value through to
build_repetition():This still respects
minLength; it just stops trying to length-cap at the grammar level for valuesthe engine can't represent as a literal repetition count anyway (arguably the right behavior even
without the threshold bug, since a length this large isn't meaningfully enforceable via GBNF
repetition).
Both patches tested locally: rebuilt
llama-server, verified the exact failing multi-tool request(10 tools including both shapes above) now parses and returns a normal completion, with no change to
grammar behavior for schemas that don't hit either edge case.
Happy to open a PR with these two changes if useful — wanted to file the bug report first in case
there's a different intended approach (e.g. whether an oversized
maxLengthshould instead berejected at the schema-validation layer with a clearer error, rather than silently uncapped).