Why LLMs Output True Instead of true (and How to Fix It)
LLMs trained on Python output True, False, and None instead of valid JSON booleans. Learn why it happens, how to fix it in Python and JavaScript, and how to prevent it with structured output in 2026.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →If you've been building with LLM APIs and noticed your JSON.parse() calls randomly failing, there's a good chance you've hit one of the most common — and least obvious — LLM JSON bugs: Python boolean literals in JSON output.
Your LLM returns this:
{"success": True, "result": None, "retry": False}
And your code throws:
SyntaxError: Unexpected token T in JSON at position 12
You can fix this instantly with AI JSONMedic — paste the broken output and get valid JSON back in one click. Or read on for a complete breakdown of why this happens and how to handle it in production.
Why This Happens
LLMs like GPT-4o, Claude, and Gemini are trained on enormous datasets that include billions of lines of Python code. In Python, booleans are True and False (capitalized), and null is None. In JSON, they must be lowercase: true, false, null.
When an LLM generates JSON without strict enforcement, it sometimes "leaks" Python syntax — particularly in responses that feel like code output rather than pure data. This is a training distribution issue: the model has seen True adjacent to dict-style data structures far more often than true in the same context.
This happens most often when:
- The prompt says "return a Python dict" or "return a dictionary"
- The model is generating code examples alongside JSON
- No JSON schema or
response_formatis specified in the API call - The model was fine-tuned on Python-heavy datasets
- The system prompt is vague: "respond in JSON" without a schema
The 3 Broken Values
| What LLMs write | What JSON requires | Python origin |
|---|---|---|
True | true | bool literal |
False | false | bool literal |
None | null | NoneType literal |
These look almost identical at a glance, which makes this bug especially painful to spot in a large payload with dozens of fields.
How to Detect It Before It Crashes
Before fixing, it helps to detect the problem programmatically so you can log and alert:
import re
def has_python_literals(text: str) -> bool:
"""Detect Python boolean/null literals in a JSON string."""
return bool(re.search(r'\b(True|False|None)\b', text))
Use before parsing
raw = llm_response.content
if has_python_literals(raw):
print(f"Warning: Python literals detected in LLM output")
raw = fix_python_literals(raw)
data = json.loads(raw)
In high-volume pipelines, log the detection rate. If it exceeds 5% of responses, your prompts need stronger enforcement.
How to Fix It
Option 1: Fix it automatically online
Paste the broken output into AI JSONMedic. It detects and repairs Python boolean literals along with every other common LLM JSON error — markdown code fences, trailing commas, truncated responses — in one click. No code required.
Option 2: Fix it in Python
import re
import json
def fix_python_literals(raw: str) -> str:
"""Replace Python literals with JSON equivalents."""
fixed = re.sub(r'\bTrue\b', 'true', raw)
fixed = re.sub(r'\bFalse\b', 'false', fixed)
fixed = re.sub(r'\bNone\b', 'null', fixed)
return fixed
def parse_llm_json(raw: str) -> dict:
fixed = fix_python_literals(raw)
return json.loads(fixed)
Example
broken = '{"active": True, "data": None, "retry": False}'
result = parse_llm_json(broken)
{"active": true, "data": null, "retry": false}
For a more robust version that also handles other LLM artifacts, use Python's ast.literal_eval as a fallback:
import ast
import json
def robust_parse(raw: str) -> dict:
# Try standard JSON first
try:
return json.loads(raw)
except json.JSONDecodeError:
pass
# Try Python literal eval (handles True/False/None)
try:
result = ast.literal_eval(raw)
if isinstance(result, dict):
# Re-serialize to get proper JSON
return json.loads(json.dumps(result))
except (ValueError, SyntaxError):
pass
# Fall back to regex fix + JSON parse
fixed = fix_python_literals(raw)
return json.loads(fixed)
ast.literal_eval is safe (it doesn't execute code) and natively understands Python's True, False, and None, making it a clean middle step before giving up.
Option 3: Fix it in JavaScript / TypeScript
If you're consuming LLM output in a Node.js or browser app, the fix looks similar:
function fixPythonLiterals(raw: string): string {
return raw
.replace(/\bTrue\b/g, 'true')
.replace(/\bFalse\b/g, 'false')
.replace(/\bNone\b/g, 'null');
}
function parseLlmJson<T>(raw: string): T {
try {
return JSON.parse(raw);
} catch {
return JSON.parse(fixPythonLiterals(raw));
}
}
See how to fix JavaScript JSON parse errors for a broader guide covering all the common failure modes in frontend and Node.js code.
Option 4: Prevent it at the source
The cleanest fix is preventing the problem before it starts. Every major provider now offers schema-enforced structured output — use it.
OpenAI (JSON mode):response = client.chat.completions.create(
model="gpt-4o",
response_format={"type": "json_object"},
messages=[{"role": "user", "content": "Return user data as JSON"}]
)
OpenAI (Strict structured output — recommended):
from pydantic import BaseModel
class UserData(BaseModel):
active: bool
data: str | None
retry: bool
response = client.beta.chat.completions.parse(
model="gpt-4o",
response_format=UserData,
messages=[{"role": "user", "content": "Return user data"}]
)
result = response.choices[0].message.parsed
Anthropic (Claude):
response = client.messages.create(
model="claude-opus-4-6",
tools=[{
"name": "output_data",
"input_schema": {
"type": "object",
"properties": {
"active": {"type": "boolean"},
"data": {"type": ["string", "null"]},
"retry": {"type": "boolean"}
},
"required": ["active", "data", "retry"]
}
}],
tool_choice={"type": "tool", "name": "output_data"},
messages=[{"role": "user", "content": "Return user data"}]
)
Google Gemini:
response = model.generate_content(
prompt,
generation_config={"response_mime_type": "application/json"}
)
For a complete guide comparing all four providers' structured output approaches, see LLM JSON Repair Guide: Fix Broken AI Output.
Why the Regex Fix Can Break
The simple regex approach works for most cases, but has one important blind spot: if your JSON string values contain the words "True", "False", or "None" as text, the regex will corrupt them.
# This breaks the regex fix:
{"message": "Status is True or False", "value": True}
Would incorrectly become:
{"message": "Status is true or false", "value": true}
The string value gets mangled. For production use, the ast.literal_eval approach is safer. Alternatively, use AI JSONMedic's API — it parses the structure first and only replaces values in the right positions.
LangChain and LlamaIndex Users
If you're using an orchestration framework, you may already have partial protection — but not complete coverage.
LangChain offersJsonOutputParser which attempts to extract and parse JSON, but it can still fail on Python literal corruption. Use PydanticOutputParser with a schema for strict validation:
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel
class MyOutput(BaseModel):
active: bool
score: float
parser = PydanticOutputParser(pydantic_object=MyOutput)
LlamaIndex has structured output via StructuredLLM — same principle applies: always define a schema.
Other LLM JSON Errors to Watch For
Python booleans aren't the only thing LLMs get wrong. Other common issues include:
- Markdown code fences — wrapping JSON in
`json`blocks - Trailing commas —
{"a": 1, "b": 2,}(valid Python, invalid JSON) - Single quotes —
{'key': 'value'}(valid Python dict, invalid JSON) - Truncated output — streaming responses cut off mid-object
- Comments —
// this is a noteinside JSON (valid JS, invalid JSON)
For a full reference of what can go wrong, see JSON Parse Error — What It Means and How to Fix It. All of these can also be repaired automatically with the JSON validator or the main AI JSON fixer.
FAQ
Why does my LLM keep outputting True even with response_format: json_object?
JSON mode (json_object) prevents non-JSON wrappers but doesn't enforce schema-level type constraints. The model can still emit Python-style booleans inside a nominally "JSON" response. Use Strict structured output (OpenAI's .parse() or Claude's tool_use with a schema) to get true type enforcement.
Is ast.literal_eval safe to use on LLM output?
Yes, in this context. ast.literal_eval only evaluates Python literals — strings, numbers, booleans, None, lists, and dicts. It does not execute arbitrary code. It's a safe parsing step when standard json.loads fails. The main limitation is that it only works if the entire string is a valid Python literal, not just part of it.
What's the fastest way to fix this in production without adding a library?
The two-pass approach: json.loads(fix_python_literals(raw)) where fix_python_literals does three str.replace() calls. Avoid regex in the hot path; string replace is faster and sufficient for the three known literals.
Does this affect Gemini differently than GPT-4o or Claude?
All three models can emit Python literals depending on the prompt. In practice, Gemini is slightly more prone to it when the prompt contains Python-style examples. GPT-4o and Claude show it less when a clear JSON instruction is given, but none are immune without schema enforcement.
What if the JSON payload is very large and partially broken?
For large, partially valid payloads, the regex fix may fix the literals but still leave other structural problems (truncation, nesting errors). In that case, use AI JSONMedic which applies multiple repair strategies in sequence, or use the json-repair Python library which tolerates a wider range of syntax errors.
Summary
LLMs output True, False, and None because they're trained on Python code — and Python's boolean literals look almost identical to JSON's. The fix depends on your environment: use ast.literal_eval in Python for a safe structural parse, a simple regex + replace for lightweight pipelines, or the JavaScript equivalent for frontend code. For production at scale, prevent the problem entirely with schema-enforced structured output. And when you're dealing with a messy payload right now, AI JSONMedic handles it in one click.
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles