Invalid control character in JSON: How to Fix It in Python
Python raises 'Invalid control character at' when a JSON string holds a raw newline, tab or other control character. Here is what causes it and how to…
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →Python raises "Invalid control character at" when a JSON string contains a raw control character, such as a real newline or tab, instead of its escaped form. Escape the character as \n or \t, or parse with strict=False if you cannot change the source.
What “Invalid control character in JSON” means
The message means the parser found a character between U+0000 and U+001F inside a string, unescaped. The JSON standard requires those characters to be escaped inside strings. Python's json module is strict by default, so it stops and reports the position as line, column and char offset. The position points at the offending character or just after it. Newline, tab and carriage return are the usual ones.
Causes and the fix for each
A raw newline sits inside a string value.
A line break typed or pasted into a string ends up as a real newline instead of the two characters \n.
Before (fails):{"note": "a
b"}
After (valid):
{"note": "a\nb"}
A raw tab sits inside a string value.
Text copied from a spreadsheet or terminal often carries real tab characters.
Before (fails):{"name": "Ann Lee"}
After (valid):
{"name": "Ann\tLee"}
A carriage return from Windows line endings sits inside a string.
A multi-line value written on Windows can bring in \r characters that were never escaped.
Before (fails):{"text": "first
second"}
After (valid):
{"text": "first\r\nsecond"}
The JSON was built by string formatting instead of json.dumps().
An f-string or concatenation puts user text into quotes without escaping it. json.dumps() escapes control characters for you.
Before (fails):{"msg": "hello
world"}
After (valid):
{"msg": "hello\nworld"}
An LLM or log pipe emitted a multi-line string unescaped.
Model output and copied logs often break a long value across real lines inside the quotes.
Before (fails):{"summary": "Step 1
Step 2"}
After (valid):
{"summary": "Step 1\nStep 2"}
How to fix it in Python
- Read the line, column and char numbers in the error. Print text[pos-20:pos+20] with repr() to see the exact character.
- If you build the JSON yourself, stop formatting strings by hand. Pass a dict to json.dumps(), which escapes newlines, tabs and other control characters.
- If the source is fixed and you cannot change it, call json.loads(text, strict=False). This setting lets control characters appear inside strings.
- If the text is a one-off file or API response, paste it into the Repair tool. The tool escapes the raw characters and returns valid JSON.
- Run the result through the Validator to confirm it parses before you use it.
- If the data comes from an LLM, ask for JSON through a tool or schema, and keep the strict=False fallback for the cases that still break.
import json
def load_json(text):
try:
return json.loads(text)
except json.JSONDecodeError as err:
if "control character" not in err.msg:
raise
# Retry while allowing raw control characters inside strings
return json.loads(text, strict=False)
data = load_json('{"note": "line one\nline two"}')
print(data["note"])
Variants of the message
| Message | Cause | Fix |
|---|---|---|
| Invalid control character at: line 2 column 12 (char 12) | Raw newline inside a string | Escape it as \n or use strict=False |
| Invalid control character at: line 1 column 15 (char 14) | Raw tab inside a string | Escape it as \t |
| Unterminated string starting at: line 1 column 10 (char 9) | String is cut off, often by a stray line break or missing quote | Close the string and escape inner line breaks |
| Invalid \escape: line 1 column 12 (char 11) | Backslash followed by a character JSON does not allow, such as a Windows path | Double the backslash |
| Expecting ',' delimiter: line 3 column 5 (char 28) | Missing comma or quote after a broken string | Fix the string, then add the missing comma |
Related errors
- Fix Python JSON Errors: json.loads() Decode Errors and How to Repair Them
- Invalid JSON Meaning: What It Is and How to Fix It
- Single quotes are not valid JSON: Fixing json.loads() in Python
- Why Computer-Use Agents Break JSON: Multi-Step Agent JSON Error Handling (2026)
Key takeaways
- The error means a raw control character sits inside a JSON string.
- Newline, tab and carriage return are the usual causes.
- Build JSON with json.dumps() instead of string formatting.
- json.loads(text, strict=False) accepts the raw characters when you cannot fix the source.
- The the Repair tool tool escapes the characters and returns valid JSON.
FAQ
What does strict=False do in json.loads()?
It allows control characters, including raw newlines and tabs, inside strings. The rest of the syntax is still checked as usual.
Is a raw newline inside a JSON string valid?
No. The JSON standard requires characters from U+0000 to U+001F to be escaped inside strings.
Why does the error say char 12 when I see the problem on another line?
The char value is a zero-based offset into the whole text. Line and column count from the start of the document, so use them together to locate the character.
Does json.dumps() produce this error?
No. json.dumps() escapes control characters in strings, so its output does not trigger this message when parsed again.
Can I just strip newlines from the text before parsing?
You can, but it also removes the line breaks between keys and values and may change the data. Escaping them inside strings keeps the content intact.
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