Jinja templates failing on llama.cpp engine but passing in Python
Parent: Mac local LLMs: llama.cpp internals · Published reference · snapshot 2026-10-05
↓ Facts as markdownall context files
llama-server returns the engine exception as an HTTP 500 body that names the node, line and column, for example "While executing FilterExpression at line 18, column 34".
These notes link each claim to its source. A source may be a research report hosted on this site rather than the primary document. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
Facts
- llama-server returns the engine exception as an HTTP 500 body that names the node, line and column, for example "While executing FilterExpression at line 18, column 34". [source]
- The engine types every value. A filter or test missing from the receiver type's table throws instead of coercing, so a template that passes a list to a string filter works only where Python is lenient. [source]
- `Undefined` is a distinct type. `message['tool_calls'] is not none` is true for a missing key, because the test is a strict type check and `Undefined` is not `None`. [source]
- Python Jinja2 accepts an undefined value as an empty iterable, so `undefined | length` works there. The C++ engine threw "filter 'length' for type Undefined" until a fix was promised on 2026-01-27. [source]
- 2026-01-17, issue 18899: a request with a tool whose schema had `"default": false` made the gpt-oss template fail with "Unknown (built-in) filter 'tojson' for type Boolean" on build 7761. On master read 2026-10-04 `tojson` is registered for int, float, string, bool, array, object and none, so this class is fixed. [source]
- 2026-01-27, issue 19130: the Apriel 1.6 Thinker GGUF template failed on `length` of undefined. A user reported it had worked before a llama.cpp change; maintainer CISC said it never worked with the new engine and that the template should use `{%- if message['tool_calls'] -%}`. [source]
- 2026-04-03, issue 21347: Gemma 4 GGUF (Unsloth) returned 500 "Unknown (built-in) filter 'upper' for type Array" because `value['type'] | upper` received a list; a user's edited template file worked around it. [source]
- 2026-06-24, PR 24971 proposed honouring `case_sensitive` in `sort` and `dictsort`; it was closed on 2026-06-25 without merging. The FIXME "sorting is currently always case sensitive" is still in `value.cpp` on master. [source]
- 2026-08-12, issue 26974: render time grew quadratically with tool count; PR 27034 fixed it on 2026-08-14. [source]
- Silent divergence: `sort(case_sensitive=false)` and `dictsort(case_sensitive=false)` are accepted and ignored, so the rendered order differs from Python with no error. [source]
- A tool schema whose `type` is a list, such as a union with null, reaches a template macro that assumed a string. A template tested only with scalar types passes in Python tests and fails in llama-server. [source]
- The 21347 reporter saw the failure on a plain "Hello" request with no tools. The source does not explain why a tool-formatting macro ran; probes that render synthetic tools at template load are a possible cause. [source]
- Render cost is a failure mode on its own: before PR 27034, a template that loops over `tools` cost 0.43 s of CPU at 20 tools by 20 properties and 128 s at 100 by 100. [source]
- A first-time fix attempt for PR 27034 that omitted a `++w != r` guard self-moved a string and silently dropped 39 bytes of prompt. [source]
- Who owns the failure. CISC (maintainer): the template is broken and should be fixed; altering engine semantics to cope would break other templates. A user (coder543): the same GGUF worked before a llama.cpp update, so the update regressed it. The two statements are not reconciled in the thread; the maintainer then added Undefined-as-iterable behaviour anyway. [source]
- How issue 18899 and issue 21347 were fixed (which commit). The issues closed without a linked fix in the data read. [source]
- Whether a Python-side conformance check (render every shipped GGUF template through both engines) exists in CI; PR 18462 reports a 370-template corpus run only. [source]
- A llama-server template exception returns HTTP 500 whose message names the node type, line and column and the error text. [source]
- Gemma 4 GGUF template failed with "Unknown (built-in) filter 'upper' for type Array" on llama.cpp build 8642. [source]
- The 21347 failure also occurred for gemma-4-E4B-it and gemma-4-E2B-it according to commenters. [source]
- A tool schema with `"default": false` produced "Unknown (built-in) filter 'tojson' for type Boolean" with the gpt-oss template on build 7761. [source]
- On master as of 2026-10-04 `tojson` is registered on bool, none, array and object value types as well as int, float and string. [source]
- The Apriel 1.6 template guard `message['tool_calls'] is not none and message['tool_calls']|length > 0` failed because a missing key is `Undefined`, which is not `None`. [source]
- Maintainer CISC stated Python Jinja2 accepts `undefined` as an iterable and said he would make the C++ engine do likewise. [source]
- Both `sort` and `dictsort` in `value.cpp` read `case_sensitive` and still carry a FIXME that sorting is always case sensitive. [source]
- PR 24971 (honour `case_sensitive`) was closed on 2026-06-25 without merging. [source]
- Issue 26974 traced 57 percent of instructions in a render to the erase loop in `gather_string_parts`. [source]
- Issue 26974 listed render times of 0.031 s (5x5), 2.425 s (40x30), 9.295 s (50x50) and 128.5 s (100x100) tools by properties for the Command-R tool-use template. [source]
- PR 27034 found two independent quadratic terms, `string::append` returning by value and the erase loop, and both had to be fixed to reach linear growth. [source]
- A template that passes under Python `apply_chat_template` can still fail under llama-server when it relies on Undefined being iterable or on list-valued schema types. [source]
Children
- No children recorded.