Skip to content

Build1 publisher2 min readPublished

Ollama's Go renderer drops the definition of any tool parameter named type or description

The Go port of Gemma's chat template filters schema keywords at all four call sites where the Jinja macro filters at one, so the parameter name reaches the model with no definition and stays on the required list.

The Engineer · Build desk

What happened

  • A tool parameter named type, description, properties, required or nullable is left out of the tool declaration Ollama's gemma4 renderer builds, while its name stays in the required list.
  • At temperature 0 on gemma4:e2b, the same ticket tool answered "type": "urgent" in both runs, for a parameter whose enum allowed only urgent_A7 and routine_B3.
  • Nothing fails: the response is HTTP 200, the tool call is well-formed JSON with the right function name, and one of its two arguments is correct.
  • The reporter, on gemma4:26b, saw the argument left out entirely and logged one ticket created out of 14 attempts against 35 schema-validation failures on a required parameter called description.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure A handler that does not validate against its own schema writes the invented string into whatever column the priority code feeds, so the bad value outlives the request that produced it.
  • constraint With no way to print the rendered prompt, the visible symptom points at the model, and the debugging goes to prompt wording, temperature and whether gemma4 can do function calling at all.
  • decision Anyone shipping tools to gemma4 on Ollama now has five words their schemas cannot use, so the field name gets chosen to suit the renderer instead of the domain.
  • precedent Reimplementing a chat template in another language makes a default argument value part of the contract, and comparing the port against the reference template in testdata did not stop this divergence shipping.

The filter lives in one Go function. Ollama renders gemma4 prompts in Go, in model/renderers/gemma4.go, and checks that renderer against the model's reference Jinja template committed under model/renderers/testdata/ [17]. In the template, the format_parameters macro takes filter_keys=false and skips the five schema keywords only when a caller asks; the macro is called four times, three of the calls pass nothing, and exactly one filters [6][18]. The Go equivalent, writeSchemaProperties, filters unconditionally and serves all four call sites [6].

urgent_A7 is a string that appears nowhere in the prompt except inside that parameter's definition [14]. Named kind, the parameter came back as urgent_A7 in both runs [13]. Named description, the same definition produced "description": "Urgent water leak.", a sentence built out of the user message, which was Open an urgent ticket titled 'Water leak' [13][11]. The only thing that changed between those requests was the name of the second parameter [12].

The two model sizes fail differently. According to the dev.to writeup, a bigger model declines to guess and a smaller one guesses, and both behaviours come from the same missing text [23]. Two runs each at temperature 0 is a determinism check, not a sample of a population [12]. For those outputs to describe your service you need a gemma4 model, a renderer carrying the unconditional filter, and a required parameter whose name is one of the five [26][9].

The reporter's numbers describe a debugging session, not the model: 35 schema-validation failures over 14 attempts is 2.5 rejected outputs per attempt, and one ticket created in 14 attempts is about 7 percent [24][25]. Every one of those failures named a required parameter called description [15]. Renaming the parameter is what showed the model had never seen it [27].

JSON Schema has no rule against property names that happen to be schema keywords. Inside properties they sit in a different namespace, and every validator handles them correctly [19]. So a validating handler and this renderer read the same document differently. A handler that does not validate stores "type": "urgent" as a priority code, and you find out later [22]. The names are ordinary ones: type is the most natural name for a categorical field, and description is what the free-text field on a ticket is called [28].

Restoring the dropped argument takes twelve lines, and the same request then returns urgent_A7 [7]. Until that lands, the fix available to you is the parameter's name [8]. Ollama has no debug setting that prints the rendered prompt, so the declaration the model actually receives can be seen only by reading the renderer or running it [16].

What to watch

  • Whether the twelve-line change lands in a release, and whether the fix covers all four call sites or only the top-level one.
  • Whether the renderer test in model/renderers/testdata/ is extended to cover a property literally named type or description.
  • Whether Ollama gains a way to print the rendered prompt, which is currently only visible by reading or running the renderer.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories