Problem Description
When using Qwen’s JSON mode in a batch request, the downstream system receives responses that do not satisfy the predefined JSON schema. Typical symptoms include:
- Missing required fields (e.g.,
"id","timestamp") - Incorrect data types (e.g.,
"score"returned as a string instead of a number) - Truncated or malformed JSON objects at the end of the batch payload
Observed error messages from the downstream validator:
Error: JSON schema validation failed: required property "id" is missing
SchemaError: type mismatch for field "score" – expected number, got string
Warning: Incomplete JSON object detected at end of batch response – truncated output
Error: Unexpected token at position 0 – response does not start with a valid JSON object
Root Cause Analysis
Multiple factors contribute to schema violations in Qwen batch processing:
- Token‑limit overflow per batch – The Qwen Model Release Notes state that a single batch request must not exceed the model’s token quota (≈ 8 k tokens). When the limit is breached, the model truncates the last response, often dropping trailing fields such as
"timestamp"or the closing brace. - Implicit “stop” token handling – In JSON mode, Qwen inserts a stop token after each JSON object. If the stop token is not correctly recognized due to a missing newline or extra whitespace, the next object may be concatenated, causing malformed structures.
- Schema‑driven prompting mismatch – The official JSON Mode specification requires the prompt to explicitly request each field with type hints. Omitting type hints leads the model to default to strings, which explains the
"score"string issue reported in GitHub issue #1589. - Batch size vs. parallelism – The Prompt Engineering Guide recommends a maximum batch size of 32 for stable JSON output. Real‑world incidents (e.g., the 2024 enterprise pipeline failure) show that batches of 50 prompts produce intermittent missing fields, correlating with internal request sharding.
Investigation and Debugging Steps
1. Capture raw HTTP response
curl -X POST https://dashscope.aliyun.com/api/v1/qwen \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-turbo",
"batch": [
{"prompt":"Extract user data", "json_mode":true, "schema":{...}},
{"prompt":"Extract transaction data", "json_mode":true, "schema":{...}}
]
}' > batch_response.json
2. Inspect token usage
jq '.batch[] | .usage.total_tokens' batch_response.json | awk '{sum+=$1} END {print "Total tokens:", sum}'
If the total exceeds the model’s limit, the response will contain a truncation warning in the error field.
3. Validate JSON structure with jq
jq -c '.' batch_response.json | wc -l
A line count lower than the batch size indicates missing or merged objects.
4. Check for stop‑token anomalies
grep -n "}" batch_response.json | head
Missing closing braces after certain indices point to stop‑token misinterpretation.
5. Review schema definition in the request
Ensure every property includes a type field, e.g.:
"schema": {
"type": "object",
"properties": {
"id": {"type": "string"},
"score": {"type": "number"},
"timestamp": {"type": "string", "format": "date-time"},
"metadata": {"type": "object"}
},
"required": ["id","score","timestamp"]
}
Resolution
1. Reduce batch size to stay within token limits
Split large batches into sub‑batches of ≤32 prompts. Example Python helper:
import math, json, requests
def chunk_batch(prompts, max_size=32):
for i in range(0, len(prompts), max_size):
yield prompts[i:i+max_size]
def send_batch(chunk):
payload = {
"model": "qwen-turbo",
"batch": [{"prompt": p, "json_mode": True, "schema": SCHEMA} for p in chunk]
}
resp = requests.post(
"https://dashscope.aliyun.com/api/v1/qwen",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json=payload
)
resp.raise_for_status()
return resp.json()
2. Enforce explicit type hints in the schema
Adding "type" for every field eliminates the string fallback observed in issue #1589.
3. Append a newline after each JSON object in the prompt
Modify the batch payload to include a trailing newline, ensuring the model emits the stop token correctly:
"prompt": "Extract user data\\n",
4. Enable response_format “strict” flag (if available)
Some Qwen releases support a strict JSON mode that rejects malformed output early:
payload["response_format"] = {"type":"json","strict":true}
Before / After Comparison
| Before (batch of 50) | After (chunks of 30 + strict mode) |
|---|---|
|
|
Verification
After applying the fixes, run the following validation pipeline:
# 1. Re‑run batch request
response=$(python send_batch.py)
# 2. Count objects
obj_count=$(echo "$response" | jq '.batch | length')
echo "Objects returned: $obj_count"
# 3. Schema validation (using jsonschema)
python - <<'PY'
import json, sys, jsonschema
SCHEMA = {...} # same as request schema
data = json.load(sys.stdin)
for obj in data['batch']:
jsonschema.validate(instance=obj, schema=SCHEMA)
print("All objects conform to schema")
PY
Successful run prints “All objects conform to schema” and the object count matches the input batch size.
Prevention and Best Practices
- Batch size limit: Keep batches ≤32 prompts or stay under the model’s token ceiling (monitor
usage.total_tokens). - Explicit schema definitions: Always include
typefor every property; avoid relying on model inference. - Strict JSON mode: Enable the
strictflag when available to catch malformed output early. - Post‑response sanity checks: Automate a lightweight
jsonschemavalidation step before downstream ingestion. - Logging token usage: Emit a metric for
total_tokensper batch; set alerts if it approaches the model limit.
Related Topic Hub: LLM Systems Troubleshooting Hub
FAQ
Why does the “timestamp” field disappear only in large batches?
When the cumulative token count exceeds the model’s per‑request limit, Qwen truncates the tail of the response. The truncation often cuts off the last field(s) of the final JSON object, which is why “timestamp” is missing in oversized batches.
How can I enforce numeric types for fields like “score”?
Include an explicit "type":"number" entry in the schema for each numeric field. The model respects these hints in JSON mode, as documented in the JSON Mode specification.
Is there a way to detect malformed JSON before parsing?
Enable the response_format.strict option (available from Qwen‑Turbo 1.2 onward). When strict mode is on, the API returns a 400 error with a descriptive message instead of a partially formed JSON payload.
What should I do if occasional “metadata” objects are missing despite correct batch size?
Intermittent missing objects are usually a symptom of token overflow caused by hidden system messages or prompt expansions. Log the exact token usage per request and adjust the prompt length or batch size accordingly.
Can I reuse the same schema across different batch jobs?
Yes, but ensure the schema version matches the model’s expectations. The Model Release Notes indicate that schema validation behavior changed in version 2.3; update your schema definitions when upgrading the model.