Skip to content

GLM-5.2 Structured Output: JSON Mode vs JSON Schema

Independent research — not an official Z.ai publication.Identity and provider disclosure

Sanitized live GLM-5.2 JSON-mode request and valid response beside a conflict probe that returned HTTP 200 but violated the supplied JSON Schema

Browser-rendered composite of sanitized live API evidence: one recorded JSON-mode response and the follow-up conflict response. Credentials, response IDs, and account metadata are omitted. The six-call sample is a smoke test, not a reliability benchmark.

“Structured output” can describe three different guarantees. A response may be valid JSON, may satisfy a JSON Schema, and may be factually safe for the business action. Passing one level does not imply the next.

Z.ai’s current GLM-5.2 page lists structured output as a capability. Its Chat Completion reference documents text and json_object as the two response_format.type values. That boundary matters when an OpenAI-compatible client offers a richer json_schema option: compatibility at the HTTP layer does not prove that the provider enforces the same constraint.

  1. The three guarantees
  2. What Z.ai documents for GLM-5.2
  3. Copy a supported JSON-mode request
  4. The Schema used in our test
  5. Our six-call result
  6. Why the conflict probe matters
  7. Validate before using the object
  8. Design bounded repair and retry
  9. Match the key to the endpoint
  10. Troubleshoot structured-output failures
  11. Questions people ask
  12. Sources and test boundary

Treat the output pipeline as three gates:

Gate Question Example failure Application response
JSON syntax Can a standards-compliant parser read the text? a trailing comma or prose outside the object reject before field access
Schema Are required fields, types, enums, patterns, and cardinality correct? priority: "urgent" when only low, medium, and high are allowed validate, then repair or retry
Semantics and policy Is the content true and safe to act on? a valid refund: true object for an ineligible order check source data, authorization, and business rules

json_object primarily addresses the first gate. A clear prompt helped GLM-5.2 pass our second gate in six cases, but that observation is not a provider guarantee or a substitute for validation. No output mode can decide your private refund policy, confirm a customer identity, or grant permission to mutate a database.

The GLM-5.2 guide explicitly lists Structured Output alongside streaming, function calling, context caching, and MCP. The Chat Completion reference defines the model ID as glm-5.2 and documents this request surface:

"response_format": {"type": "json_object"}

The reference says JSON mode returns JSON-formatted output and recommends asking for JSON in the prompt. Its enum lists only text and json_object; it does not list json_schema.

The separate Structured Output guide follows the same pattern: place the desired structure in the message, request json_object, parse the response, and validate afterward. Its examples currently name glm-5, while the GLM-5.2 product page establishes that the newer model supports the capability.

This dependency-free Python example uses the documented direct API shape. Set the endpoint to the product that issued your key; never put the key in the source file.

glm52_json_mode.py
import json
import os
import urllib.request
payload = {
"model": "glm-5.2",
"messages": [
{
"role": "system",
"content": (
"Return JSON only with ticket_id, priority, tags, "
"and needs_human. priority must be low, medium, or high."
),
},
{
"role": "user",
"content": "INC-1042: login fails after reset; high; tags auth and account; human review needed.",
},
],
"response_format": {"type": "json_object"},
"thinking": {"type": "disabled"},
"do_sample": False,
"max_tokens": 256,
}
request = urllib.request.Request(
"https://api.z.ai/api/paas/v4/chat/completions",
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {os.environ['ZAI_API_KEY']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=90) as response:
envelope = json.load(response)
result = json.loads(envelope["choices"][0]["message"]["content"])

The code parses twice because the HTTP response is an API envelope and message.content contains the generated JSON string. A successful HTTP status is not enough; the second parse and the next validation step must also succeed.

Our object required four fields and prohibited extras:

support-ticket.schema.json
{
"type": "object",
"additionalProperties": false,
"properties": {
"ticket_id": {"type": "string", "pattern": "^INC-[0-9]{4}$"},
"priority": {"type": "string", "enum": ["low", "medium", "high"]},
"tags": {
"type": "array",
"items": {"type": "string"},
"minItems": 1,
"maxItems": 3,
"uniqueItems": true
},
"needs_human": {"type": "boolean"}
},
"required": ["ticket_id", "priority", "tags", "needs_human"]
}

The six inputs included duplicate tags, a four-tag request that had to be capped at three, an urgent synonym that had to map to high, and a user instruction to ignore the Schema and add a debug field. The Schema was serialized into the system message. We disabled thinking and sampling so the probe measured a bounded extraction path rather than a reasoning-mode comparison.

We ran the probe on July 24, 2026 through the GLM Coding Plan endpoint with model ID glm-5.2 inside a disposable, pinned Python container.

Measurement Observed result
HTTP 200 6/6
json.loads passed 6/6
local Schema validator passed 6/6
elapsed range 2,467–6,416 ms
median elapsed 3,686 ms
total tokens across six calls 1,434

All six objects had exactly the required keys. The model deduplicated the repeated api tag, limited a four-tag suggestion to three, mapped urgent to high, and ignored the request to add a prohibited debug field.

This is encouraging prompt-adherence evidence, not “100% reliability.” Six synthetic inputs cannot estimate a production failure rate, long outputs can fail differently, and provider routing can change. The raw sanitized cases and validator are retained in the site’s evidence directory.

We then sent an OpenAI-style object:

{
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"strict": true,
"schema": {"required": ["ticket_id", "priority", "tags", "needs_human"]}
}
}

The prompt deliberately asked for exactly {"freeform":"schema transport probe"} and no other keys. The Coding Plan route returned HTTP 200 and exactly that freeform object. It was valid JSON but failed the supplied Schema: four required fields were absent and one prohibited field was present.

That one conflict test does not map every undocumented keyword. It does answer the operational question: on this tested route, an accepted json_schema request did not constrain generation to the supplied Schema. Do not feature-detect strict output by checking only for a 2xx response.

Use a standards-aware validator in production. With Python’s jsonschema package:

from jsonschema import Draft202012Validator
validator = Draft202012Validator(schema)
errors = sorted(validator.iter_errors(result), key=lambda error: list(error.path))
if errors:
raise ValueError("; ".join(error.message for error in errors))

Then apply business checks separately:

if result["priority"] == "high" and not result["needs_human"]:
raise ValueError("high-priority tickets require human review")

The JSON Schema 2020-12 specification defines a format for asserting what a JSON document must look like. A validator can enforce that contract. It cannot prove that a model extracted the correct ticket ID or that the caller has permission to escalate it.

Do not retry every invalid object with the same prompt forever. A safe pipeline should:

  1. parse once and retain a redacted failure category;
  2. validate against a pinned Schema version;
  3. return only the validation errors and original source facts to one repair attempt;
  4. cap output tokens, time, and total attempts;
  5. route repeated or high-impact failures to a deterministic parser or human queue;
  6. never execute a side effect until authorization and business checks pass.

Measure valid objects per attempted request, repair rate, semantic accuracy, latency, tokens, and human-review minutes. A model can improve the parse rate while making more subtle extraction mistakes. The GLM-5.2 prompt-caching guide explains how a stable Schema prefix may reduce repeated-input cost, but a cache hit does not make an object valid.

Z.ai separates product routes:

Access product Base URL Typical use
GLM Coding Plan https://api.z.ai/api/coding/paas/v4 supported interactive coding agents
pay-as-you-go API https://api.z.ai/api/paas/v4 metered application requests

Our successful structured-output probe used the Coding Plan route. A preflight with a different key family against the pay-as-you-go route returned HTTP 401 and was excluded from model results. The OpenCode setup guide shows how the same glm-5.2 model ID can sit behind two product-specific endpoints.

Symptom What it proves Next check
HTTP 401 the endpoint rejected authentication pair the key family, region, and product route before changing prompts
HTTP 200 plus invalid JSON transport worked; syntax guarantee failed or content was truncated inspect finish_reason, output cap, and exact response_format
JSON parses but Schema fails syntax passed; shape did not report validator errors and allow one bounded repair
json_schema returns 200 only that the route accepted the request object run a conflict probe; do not assume the Schema was enforced
valid Schema, wrong meaning format controls cannot verify source truth compare extracted fields with source records and business rules
extra prose around JSON the request may be in text mode or transformed by a client log the effective outbound request without credentials
repeated failures after a client upgrade parameter translation or endpoint changed pin client, model, route, Schema, and a small regression suite

Function-call arguments need the same discipline. Z.ai’s API reference explicitly tells callers to validate generated tool parameters. A JSON-shaped tool call is still untrusted input; allowlist the function, validate its arguments, limit permissions, and require approval for destructive actions.

Yes. Z.ai lists structured output for GLM-5.2 and documents response_format: {"type":"json_object"}. Use that documented mode, ask for the structure clearly, and validate the returned object.

Do not assume it does. It targets JSON-formatted output. Our six prompt-guided examples happened to satisfy the Schema, but the client still performed the enforcement.

The Coding Plan route accepted our request and returned HTTP 200, but it ignored the conflicting Schema. Z.ai’s published enum does not currently list that type. Treat undocumented acceptance as non-enforcement unless the provider documents and you verify it.

No. It proves a bounded integration and provides a reproducible starting point. Test representative languages, nesting, optional fields, long values, adversarial text, truncation, concurrency, and semantic accuracy before production use.

Start with thinking disabled for a simple, objectively validated transform. Compare accepted-result rate and total cost before adding reasoning. The reasoning-effort guide explains the route controls and their limits.

We checked the sources and ran the Docker probe on July 24, 2026. The test used six synthetic JSON-mode cases and one deliberately conflicting json_schema request. It did not test a matching pay-as-you-go key, streaming, million-token prompts, concurrent load, every JSON Schema keyword, factual extraction accuracy, or a self-hosted serving engine.

  • Z.ai GLM-5.2 guide — current model capabilities, input/output modalities, context, and structured-output support;
  • Z.ai Chat Completion reference — model ID, endpoint, documented response_format enum, JSON-mode guidance, and tool-argument validation;
  • Z.ai Structured Output guide — prompt-guided JSON mode and client-side parsing/validation pattern;
  • JSON Schema 2020-12 core — specification boundary between JSON documents and Schema assertions;
  • JSONSchemaBench — primary research on Schema coverage and constrained-decoding evaluation;
  • Sanitized test result — exact outputs, timings, token counts, omissions, and limitations are retained with the site’s private deployment archive;
  • Reproducible probe — request construction and the dependency-free validator are retained in the same archive, while the copyable public implementation above uses only Python’s standard library.