Recipes
Debug Broken JSON
Your mock responds, but the JSON comes back as unformatted raw text, or the client refuses to parse it. This page is a checklist of the four template bugs that cause almost every broken JSON body, in the order you should suspect them.
How Mocko tells you
When a mock declares a JSON content type, Mocko validates the rendered body. Valid JSON is pretty-printed automatically; invalid JSON is returned as-is, and the server logs an error saying the body was not valid JSON. So an unformatted response is the signal: the template rendered something broken.
Suspect 1: a trailing comma from each
The classic. isLast only exists inside forEach. Inside each it is undefined, so the negated block {{^isLast}},{{/isLast}} renders its comma on every iteration, including the last:
{{! BROKEN: renders [1,2,3,] }}
[
{{#each data.catalog.product}}
{{$this.id}}{{^isLast}},{{/isLast}}
{{/each}}
]
{{! FIXED: forEach provides a real isLast }}
[
{{#forEach data.catalog.product}}
{{item.id}}{{^isLast}},{{/isLast}}
{{/forEach}}
]forEach.Suspect 2: an empty value from a context change
A field renders as nothing, leaving invalid JSON like "id": ,. The usual cause: reading request or data inside a block that changed the context, such as forEach, each, with, or a direct object block:
{{! BROKEN: request is out of scope inside the loop }}
{{#forEach data.catalog.product}}
{ "id": {{item.id}}, "requestedBy": "{{request.headers.x-user}}" }{{^isLast}},{{/isLast}}
{{/forEach}}
{{! FIXED: extract to a variable first }}
{{= $user request.headers.x-user}}
{{#forEach data.catalog.product}}
{ "id": {{item.id}}, "requestedBy": "{{$user}}" }{{^isLast}},{{/isLast}}
{{/forEach}}$root.request... also works when a variable feels like overkill. The mechanics are explained on the Templating page. A related empty-value case: reading a named data sub-block as if it were an object. Sub-blocks are always arrays, see Data Blocks.
Suspect 3: missing quotes around a string
Template expressions render bare values; JSON string syntax is your job. "name": {{item.name}} renders "name": Widget, which is not JSON. Keep the quotes in the template: "name": "{{item.name}}". Numbers and booleans go unquoted; strings do not.
Suspect 4: literal braces
A body containing braces that are not template syntax, common when a payload embeds nested closing braces or example templates, fails to parse or renders oddly. Escape them as \{{ and \}}. In HCL quoted strings (not heredocs) double the backslash: \\{{.
Tools for narrowing it down
{{log 'here'}}prints to the server console, confirming which branch ran. Dump values with{{log (json request.body)}}.- Templates that fail to compile are reported when the mock loads, with a line and column pointer in the terminal, and on the mock itself in the UI.
- Bisect big templates: comment out half the body with
{{! ... }}and see if the JSON becomes valid.