JSON Unterminated String Error: Causes and Fixes (2026)
Getting a JSON 'Unterminated string starting at' error? Learn why it happens (LLM truncation, Windows paths, backslashes) and how to auto-repair it in JavaScript, Python, or online.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →A JSON unterminated string error means the parser found an opening " that never had a matching closing ". The string value started but the document ended — or something broke the string boundary — before it could close.
This is one of the most common JSON errors in AI-generated output and LLM pipelines in 2026, with active GitHub issues across LiteLLM, LangChain, Mastra, and OpenAI's own community forum all reporting the same pattern.
What the Error Looks Like
The exact message depends on the runtime, but all point to the same problem:
| Runtime | Error Message |
|---|---|
| Python | json.decoder.JSONDecodeError: Unterminated string starting at: line X column Y |
| Node.js / Browser | SyntaxError: Unterminated string in JSON at position N |
| Java (Gson) | com.google.gson.JsonSyntaxException: Unterminated string |
| Go | invalid character '\n' in string literal |
| Ruby | JSON::ParserError: An opening quotation mark... |
| PHP | json_last_error() === JSON_ERROR_SYNTAX |
Here's a minimal example:
{
"message": "Hello, this string never closes,
"status": "ok"
}
The parser reads "Hello, this string never closes, and then encounters a newline — which is not allowed inside a JSON string unless it's escaped as \n. The string is considered unterminated from that point.
Why Unterminated String Errors Happen
LLM Output Truncation (Most Common in 2026)
The most frequent cause in modern pipelines: a language model generates JSON but gets cut off by a token limit. The output stops mid-string:
# LLM asked to return a JSON summary
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this document as JSON"}],
max_tokens=150 # Too low for the expected output
)
# Returns: {"summary": "This document covers the history of Byzantine architecture and its inf
# Missing: closing " } — string is unterminated
Active reports of this pattern:
- LiteLLM #25985 (Jul 2026): Ollama chat transformation fails with
JSONDecodeError: Unterminated stringwhen parsing tool call arguments - LangChain.js #2327: Structured output failures with unterminated strings
- Mastra #9958:
SyntaxError: Unterminated string in JSONin LLM execution steps - Graphiti #1204: Entity extraction breaks on LaTeX content with backslashes
When max_tokens is too low, the model just stops generating. If it stopped inside a string value, you get an unterminated string.
max_tokens. For structured JSON output, estimate the expected output size and budget at least 2x that in tokens.
Raw Newlines Inside String Values
JSON strings cannot contain literal newlines. This is correct JSON:
{ "text": "Line one\nLine two" }
This is not:
{
"text": "Line one
Line two"
}
The second example breaks the string at the newline. This happens when you build JSON by string concatenation from multi-line text values, or when an LLM generates JSON with natural paragraph breaks.
Unescaped Backslashes (LaTeX / Windows Paths)
A backslash that isn't part of a valid JSON escape sequence can terminate or break a string. JSON only allows these escape sequences: \", \\, \/, \n, \r, \t, \b, \f, and \uXXXX.
Anything else — \U, \d, \p, \x, \' — is invalid:
{ "path": "C:\Users\Documents\report.pdf" }
// ^ ^ ^
// \U, \D, \r are invalid — \r is actually "carriage return" here (valid escape but wrong intent)
// \U and \D are invalid escapes
Or LaTeX in an AI pipeline:
{ "formula": "The equation is \(\alpha + \beta = \gamma\)" }
// ^ \( is not a valid JSON escape
This becomes an unterminated string error because the parser may interpret \( as a malformed escape and fail to find the expected closing ".
Missing Closing Quote
A straightforward typo — the closing " is simply absent:
{
"name": "Alice,
"role": "admin"
}
The "Alice, string never closes. The parser reads "Alice,\n "role" as one long string value and never finds the structural : it expects.
Quote Characters Inside String Values
If your string contains a literal " character and it isn't escaped with \", the parser treats it as the end of the string value:
{ "message": "He said "hello" to everyone" }
// ^ ^
// Parser sees: string = "He said "
// Then doesn't know what to do with: hello
How to Find an Unterminated String Error
Method 1: Use a JSON Validator
Paste the JSON into AI JSONMedic. The validator identifies the exact line and column where the unterminated string starts. The error position points to the opening " of the unterminated string — the problem is that there's no matching close quote before the next structural character.
Method 2: Python's Built-In Error Position
Python's json module gives you line and column numbers:
import json
broken = '{"message": "This string is unterminated, "status": "ok"}'
try:
json.loads(broken)
except json.JSONDecodeError as e:
print(f"Error: {e.msg}")
print(f"Line: {e.lineno}, Column: {e.colno}")
print(f"Character position: {e.pos}")
# Shows you exactly where the parser failed
Method 3: Find Unescaped Newlines in Strings
import re
def find_unescaped_newlines(json_str: str):
"""Find raw newlines inside JSON string values."""
# Matches content inside double quotes, looks for literal newlines
pattern = r'"(?:[^"\\]|\\.)*\n(?:[^"\\]|\\.)*"'
matches = list(re.finditer(pattern, json_str, re.DOTALL))
for m in matches:
print(f"Unterminated string candidate at position {m.start()}: {repr(m.group()[:60])}")
return len(matches) > 0
broken = '{"text": "Hello\nWorld", "ok": true}'
find_unescaped_newlines(broken) # Flags the string with raw newline
How to Fix an Unterminated String
Fix 1: Auto-Repair Online
Paste the broken JSON into AI JSONMedic. The repair engine detects unterminated strings, adds the missing closing quote in the right position, and returns valid JSON. This is the fastest fix for one-off errors.
Fix 2: Repair in Python
import json
from jsonrepair import repair_json # pip install jsonrepair
def safe_parse(raw: str) -> dict:
"""Parse JSON, repairing unterminated strings if needed."""
try:
return json.loads(raw)
except json.JSONDecodeError:
repaired = repair_json(raw)
return json.loads(repaired)
# LLM truncation example
truncated = '{"summary": "The document discusses Byzantine architecture and its inf'
result = safe_parse(truncated)
print(result)
# {"summary": "The document discusses Byzantine architecture and its inf"}
# (repair closes the string and object)
The jsonrepair package handles unterminated strings, missing brackets, trailing commas, unquoted keys, and about a dozen other common patterns in a single call.
Fix 3: Repair in JavaScript / Node.js
import { jsonrepair } from 'json-repair'; // npm install json-repair
function safeParse(raw) {
try {
return JSON.parse(raw);
} catch {
const repaired = jsonrepair(raw);
return JSON.parse(repaired);
}
}
// Unterminated string from LLM
const broken = '{"title": "Introduction to JSON, "count": 5}';
const result = safeParse(broken);
console.log(result); // { title: 'Introduction to JSON', count: 5 }
Fix 4: Escape Backslashes for Windows Paths
If the unterminated string comes from a Windows file path, escape all backslashes:
import json
# Problem: unescaped Windows path
raw_path = r"C:\Users\Alice\Documents\report.pdf"
# Fix: double the backslashes before encoding
escaped_path = raw_path.replace("\\", "\\\\")
json_str = json.dumps({"path": raw_path}) # json.dumps does this automatically
print(json_str)
# {"path": "C:\\Users\\Alice\\Documents\\report.pdf"}
# If building JSON strings manually (don't do this — use json.dumps):
manual = '{"path": "' + raw_path.replace("\\", "\\\\") + '"}'
print(json.loads(manual)) # Works
Always use json.dumps() / JSON.stringify() to serialize values. Never build JSON strings by concatenation — it's how escape errors slip in.
Fix 5: Escape Newlines in Multi-Line Text
import json
multi_line = """This is paragraph one.
This is paragraph two with a newline."""
# Wrong — creates unterminated string in JSON:
# manual = '{"text": "' + multi_line + '"}' # DO NOT DO THIS
# Right — let json.dumps handle the escaping:
correct = json.dumps({"text": multi_line})
print(correct)
# {"text": "This is paragraph one.\n\nThis is paragraph two with a newline."}
Fix 6: Escape Quotes in String Values
import json
# Value contains quotes
value = 'He said "hello" to everyone'
# json.dumps escapes the internal quotes automatically:
result = json.dumps({"message": value})
print(result)
# {"message": "He said \"hello\" to everyone"}
# Manual fix if you receive raw JSON with unescaped quotes:
broken = '{"message": "He said "hello" to everyone"}'
repaired = repair_json(broken) # jsonrepair handles this
Fixing LLM Unterminated Strings in Production
For AI pipelines that generate JSON, add a two-step parse with repair:
import json
import logging
from jsonrepair import repair_json
logger = logging.getLogger(__name__)
def parse_llm_json(raw: str) -> dict:
"""
Parse LLM-generated JSON with automatic repair for unterminated strings.
Logs all repair events for monitoring.
"""
if not raw or not raw.strip():
raise ValueError("Empty response from LLM")
# Step 1: Try strict parse (zero overhead when valid)
try:
return json.loads(raw)
except json.JSONDecodeError as original_err:
pass
# Step 2: Attempt repair
try:
repaired = repair_json(raw)
result = json.loads(repaired)
logger.warning(
"Repaired LLM JSON",
extra={"error": str(original_err), "original_length": len(raw)}
)
return result
except Exception as repair_err:
raise ValueError(
f"Unrecoverable JSON from LLM: {repair_err}\n"
f"Input (first 300 chars): {raw[:300]}"
)
Prevention checklist for LLM JSON pipelines:
- Increase
max_tokens— size it to at least 2x the expected JSON output - Use structured output — OpenAI, Anthropic, and Gemini all offer schema-constrained generation that prevents many string errors
- Avoid LaTeX/backslash content in prompts if the LLM must embed it in JSON — or instruct the model to escape backslashes explicitly
- Use
json.dumps()/JSON.stringify()when building JSON programmatically — never concatenate
FAQ
Q: Python says "Unterminated string starting at: line 1 column 15" — what does that mean?It means at character position 15, the parser found an opening " that never had a matching " before the end of the document (or before an invalid character). The error position is where the string started, not where it ended. Look at what comes after position 15 — the closing quote is missing or preceded by an invalid character.
Most likely the data changed — a string value now contains a character that breaks the JSON. Common culprits: a new multi-line text value with raw newlines, a user-submitted string with unescaped quotes, or an LLM response that got longer and hit a token limit. Check what changed in the data, not the structure.
Q: Canjson-repair fix an unterminated string without losing data?
For truncated strings (LLM cutoff), the repair closes the string at the truncation point — the data up to the cutoff is preserved, nothing after it exists. For strings broken by an invalid character (raw newline, bad escape), the repair attempts to reconstruct the intent, which is usually correct but may occasionally need a manual review. Always validate the repaired output before using it in production.
Q: I have a JSON file with hundreds of unterminated strings (bulk data). How do I fix all of them?Run the file through jsonrepair programmatically:
from jsonrepair import repair_json
with open("broken.json") as f:
broken = f.read()
fixed = repair_json(broken)
with open("fixed.json", "w") as f:
f.write(fixed)
Or use the JSON Studio file upload to repair and download in one step.
Q: Is an unterminated string different from a missing closing bracket?Yes. A missing bracket (} or ]) leaves a structural container unclosed. An unterminated string leaves a value unclosed. Both produce "unexpected end of JSON input" style errors, but the fix is different: missing brackets need } or ] appended, unterminated strings need " inserted at the right point. See JSON Missing Bracket Error Fix for the bracket-specific guide.
Double every backslash before encoding: \alpha becomes \\alpha. In Python, json.dumps() handles this automatically if you pass the string as a Python value. If you're prompting an LLM to generate JSON containing LaTeX, instruct it explicitly: "All backslashes in the JSON must be doubled (\\\\alpha not \\alpha)."
Related Resources
- JSON Missing Bracket Error Fix — for unclosed
{or[errors - JSON Trailing Comma Error Fix — another common LLM-generated JSON issue
- LLM JSON Repair Guide — full guide to AI-generated JSON failures
- Fix Python JSON Errors — Python-specific json.decoder.JSONDecodeError guide
- JSON Syntax Errors Explained — full taxonomy of JSON error types
- AI JSONMedic JSON Studio — repair, validate, and format JSON in one workspace
An unterminated string is always fixable. The fastest path: paste into AI JSONMedic and get valid JSON back in one click. For LLM pipelines, add a jsonrepair fallback to your parse logic and increase max_tokens — those two changes eliminate the majority of unterminated string failures in production.
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