When a JSON file does not load, the message you get depends on who read it. Python says Expecting value, Chrome says Unexpected token, jq says Invalid numeric literal, and PowerShell 7 often says nothing at all. Behind those different words there are about twenty mistakes that come up again and again in configuration files, API payloads and script output.
This page lists each of them under the same name the JSON formatter and validator uses, so a link from the tool lands on the right section. Every entry shows where the mistake usually comes from in admin work, a broken and a fixed example, and a link that opens the broken example in the formatter so you can see the error and the fix on screen.
The parser messages quoted below were captured from Python 3.11, Node.js 22 (the same engine and messages as Chrome), jq 1.7 and PowerShell 7.4 by feeding each of them the same broken samples.
Find your error by the message you got
Search this page (Ctrl+F) for a few words of your message, or use the tables below. The link in the last column goes to the section that explains it.
Python (json.loads, json.load)
| Message starts with | Most likely cause |
|---|---|
Expecting value | trailing comma in an array, extra comma, unquoted text, True / None, PowerShell hashtable, +1 or .5, empty input |
Expecting property name enclosed in double quotes | trailing comma in an object, single quotes, key without quotes, curly quotes, comment |
Expecting ',' delimiter | missing comma, unclosed bracket, wrong closing bracket, leading zero or hex number |
Expecting ':' delimiter | missing colon |
Extra data | text after the JSON value |
Unterminated string starting at | string never closed |
Invalid control character at | tab or line break inside a string |
Invalid \escape | backslash in a Windows path |
Unexpected UTF-8 BOM (decode using utf-8-sig) | byte order mark |
Chrome, Edge and Node.js (JSON.parse, fetch().json())
| Message contains | Most likely cause |
|---|---|
Unexpected token ']' | trailing comma in an array |
Unexpected token ',' | extra comma |
Expected double-quoted property name | trailing comma before } |
Expected property name or '}' | single quotes, unquoted key, curly quotes, comment |
Expected ',' or '}' after property value | missing comma, unclosed object, hex number |
Expected ',' or ']' after array element | wrong closing bracket |
Expected ':' after property name | missing colon |
Unexpected end of JSON input | empty or cut-off input |
Unexpected non-whitespace character after JSON | second value or trailing text |
Unterminated string in JSON | string never closed |
Bad control character in string literal | tab or line break in a string |
Bad escaped character | backslash in a path |
Unexpected number in JSON | number with a leading zero |
Unexpected token 'N', 'T', '@', 'p' | NaN, True, @{ } or @, unquoted word |
| Unexpected token followed by an invisible character | BOM or non-breaking space |
jq
| Message contains | Most likely cause |
|---|---|
Expected another array element | trailing comma in an array |
Expected another key-value pair | trailing comma in an object |
Expected value before ',' | extra comma |
Expected separator between values | missing comma or missing colon |
Unfinished JSON term at EOF | unclosed bracket |
Objects must consist of key:value pairs | wrong closing bracket |
Invalid numeric literal | jq's catch-all for text it cannot read: single quotes, unquoted key, unquoted value, True / None, comment, curly quotes, invisible space |
Unfinished string at EOF | string never closed |
Invalid string: control characters | tab or line break in a string |
Invalid escape | backslash in a path |
PowerShell 7 (ConvertFrom-Json)
PowerShell 7 wraps every message in Conversion from JSON failed with error:. The part after it tells you the cause.
| Message contains | Most likely cause |
|---|---|
After parsing a value an unexpected character was encountered | missing comma |
Invalid character after parsing property name. Expected ':' | missing colon |
Unexpected end when deserializing object | unclosed bracket |
JsonToken EndObject is not valid for closing JsonType Array | wrong closing bracket |
Additional text encountered after finished reading JSON content | second value or trailing text |
Unexpected character encountered while parsing value | unquoted text, True / None, hashtable, @ or $, plus sign |
Invalid property identifier character | curly quotes |
Unterminated string. Expected delimiter | string never closed |
Bad JSON escape sequence | backslash in a path |
It works in PowerShell but the application rejects it
This is the most common trap for Windows admins. ConvertFrom-Json in PowerShell 7 is a forgiving reader: it quietly accepts several things that the JSON standard forbids. You edit a file, check it with Get-Content file.json | ConvertFrom-Json, get no error, and then the application, the Azure deployment or a Python script refuses the same file.
The table shows what each reader did with the same samples. "Accepted" means no error was raised, not that the data came out right.
| Sample | Chrome / Node | Python | jq 1.7 | PowerShell 7 ConvertFrom-Json | PowerShell 7 Test-Json |
|---|---|---|---|---|---|
| Trailing comma | Rejected | Rejected | Rejected | Accepted | Rejected |
| Single quotes | Rejected | Rejected | Rejected | Accepted | Rejected |
| Key without quotes | Rejected | Rejected | Rejected | Accepted | Rejected |
| // comment | Rejected | Rejected | Rejected | Accepted | Rejected |
| Tab inside a string | Rejected | Rejected | Rejected | Accepted | Rejected |
Empty item ["a",,"b"] | Rejected | Rejected | Rejected | Accepted, reads it as null | Rejected |
Leading zero 0443 | Rejected | Rejected | Accepted, reads 443 | Accepted, reads 291 | Rejected |
Hex 0x1F | Rejected | Rejected | Rejected | Accepted, reads 31 | Rejected |
| NaN | Rejected | Accepted | Accepted | Accepted | Rejected |
0443 as an octal number and returns 291. A port, an employee number or a site code written with a leading zero comes back as a different value with no warning.
To check a file the way strict applications will read it, use Test-Json (PowerShell 6.1 and later) instead of ConvertFrom-Json, or paste it into the formatter:
# Test-Json follows the standard; ConvertFrom-Json does not
Test-Json -Json (Get-Content -Raw .\appsettings.json)
# False, plus a "Cannot parse the JSON" error, when the file would fail elsewhere
Commas, brackets and structure
Trailing comma
zaur.it shows: trailing comma before ] or trailing comma before }. This one can be repaired with Fix automatically.
Where it comes from: deleting the last line of a list in an editor and leaving the comma on the line above, or building JSON by string concatenation in a loop that appends a comma after every item. JavaScript, PowerShell arrays and .NET appsettings.json tolerate it, so the habit sticks.
Broken:
{
"servers": ["sql01", "sql02",],
"port": 1433,
}
Fixed:
{
"servers": ["sql01", "sql02"],
"port": 1433
}
Open this example in the JSON formatter
Missing comma between items
zaur.it shows: missing comma between items.
Where it comes from: adding a new property at the end of a config file by hand and forgetting to put a comma after the line that used to be last.
Broken:
{
"name": "sql01"
"port": 1433
}
Fixed:
{
"name": "sql01",
"port": 1433
}
Open this example in the JSON formatter
Extra comma (empty item)
zaur.it shows: extra comma (empty item).
Where it comes from: removing an item from the middle of a list and leaving both commas behind.
Broken:
{
"dns": ["10.0.0.10",,"10.0.0.11"]
}
Fixed:
{
"dns": ["10.0.0.10", "10.0.0.11"]
}
null, so the list silently gains an extra item.
Open this example in the JSON formatter
Missing colon
zaur.it shows: missing colon after "name", or = instead of : after "name". Fix automatically repairs it when the fix is unambiguous: = becomes :, and a missing colon is inserted only when a value follows the key directly and is itself followed by , or }.
Where it comes from: writing a JSON object from memory after working with PowerShell hashtables or INI files, where the separator is =.
Broken:
{
"name" = "sql01",
"port" 1433
}
Fixed:
{
"name": "sql01",
"port": 1433
}
Open this example in the JSON formatter
Unclosed bracket
zaur.it shows: object opened on line 1 is never closed, with the line where the bracket was opened.
Where it comes from: a truncated copy: output cut at the console width, a log line limit, a clipboard paste that stopped early, or an API response interrupted by a timeout.
Broken:
{
"name": "sql01",
"tags": ["db", "prod"]
Fixed:
{
"name": "sql01",
"tags": ["db", "prod"]
}
Python reports this as Expecting ',' delimiter at the very end of the input, which points at the wrong problem. If the position is the last character of the file, look for a missing } or ] first. If the input was cut off, add the bracket only after checking that nothing else is missing.
Open this example in the JSON formatter
Wrong closing bracket
zaur.it shows: } where ] was expected.
Where it comes from: editing nested structures by hand: an array inside an object closed with }, or the closing brackets typed in the wrong order.
Broken:
{
"tags": ["db", "prod"}
}
Fixed:
{
"tags": ["db", "prod"]
}
Open this example in the JSON formatter
Empty or cut-off input
zaur.it shows: no JSON value, or input ends where a value was expected.
Where it comes from: a zero-byte file written by a failed redirect or an empty Out-File, an API call that returned an empty body, or input cut off right after a key or a comma. In the browser this is the familiar Unexpected end of JSON input from fetch().json() on an empty response.
Broken:
{
"name": "sql01",
"port":
Fixed:
{
"name": "sql01",
"port": 1433
}
jq -e or check the file size first.
Open this example in the JSON formatter
Text after the JSON value
zaur.it shows: a second JSON value, or text after the JSON value.
Where it comes from: JSON Lines logs, where every line is a separate JSON object; output appended to the same file twice; or a shell prompt such as PS C:\> copied together with the output.
Broken:
{"event": "logon", "user": "j.meyer"}
{"event": "logoff", "user": "j.meyer"}
Fixed:
[
{"event": "logon", "user": "j.meyer"},
{"event": "logoff", "user": "j.meyer"}
]
A file with one object per line is valid JSON Lines, not invalid JSON. jq reads it natively; most other tools want one document. Wrap the objects in an array as above, or check one line at a time.
Open this example in the JSON formatter
Unexpected character
zaur.it shows: unexpected character @, colon inside an array, or unexpected } where a key was expected.
Where it comes from: template placeholders that were never replaced ({{port}}, @server), a key-value pair written inside [ ], or a stray character from editing. A placeholder that starts with a letter, such as $env:COMPUTERNAME, is reported as text without quotes instead.
Broken:
{
"server": "SRV-WEB-01",
"port": {{port}},
"roles": ["web": true]
}
Fixed:
{
"server": "SRV-WEB-01",
"port": 8443,
"roles": {"web": true}
}
Open this example in the JSON formatter
Strings and quotes
Single quotes
zaur.it shows: string in single quotes. This one can be repaired with Fix automatically.
Where it comes from: Python print(my_dict) or str(my_dict) instead of json.dumps(), JavaScript object literals, and PowerShell, where single-quoted strings are normal.
Broken:
{'name': 'sql01', 'port': 1433}
Fixed:
{"name": "sql01", "port": 1433}
Open this example in the JSON formatter
Curly quotes
zaur.it shows: curly quote “ instead of ". This one can be repaired with Fix automatically.
Where it comes from: JSON pasted into Word, Outlook, Teams or OneNote and copied back out. Autocorrect replaces straight quotes with typographic ones, which look almost the same on screen.
Broken:
{“name”: “sql01”}
Fixed:
{"name": "sql01"}
This is one of the few mistakes PowerShell 7 does reject, with Invalid property identifier character: “. To avoid it, send JSON as a file attachment or inside a code block, not as message text.
Open this example in the JSON formatter
Key without quotes
zaur.it shows: key without quotes: name.
Where it comes from: JavaScript object literals and YAML habits. PowerShell 7 accepts unquoted keys, so a file checked only with ConvertFrom-Json keeps them.
Broken:
{name: "sql01", port: 1433}
Fixed:
{"name": "sql01", "port": 1433}
Open this example in the JSON formatter
Text without quotes
zaur.it shows: text without quotes: production, or TRUE in capitals.
Where it comes from: a string value typed without quotes, or a boolean written in capitals. JSON has exactly three bare words: true, false and null, all lowercase.
Broken:
{"env": production, "enabled": TRUE}
Fixed:
{"env": "production", "enabled": true}
Open this example in the JSON formatter
String never closed
zaur.it shows: string is never closed.
Where it comes from: a closing quote deleted while editing, or a value cut off in the middle.
Broken:
{"description": "Primary SQL node}
Fixed:
{"description": "Primary SQL node"}
A double quote inside the text causes a different error. In "Primary "SQL" node" the string ends after Primary , and the formatter reports a missing comma before SQL. Escape inner quotes as \": "Primary \"SQL\" node".
Open this example in the JSON formatter
Tab or line break inside a string
zaur.it shows: tab inside a string, line break inside a string, or control character U+0000 inside a string.
Where it comes from: a value copied from an Excel cell (tabs), a multi-line note or certificate pasted straight into the file, or a file edited in an editor that turned \n into a real line break.
Broken:
{"note": "Patched in September
Reboot pending"}
Fixed:
{"note": "Patched in September\nReboot pending"}
Open this example in the JSON formatter
Backslash in a Windows path
zaur.it shows: invalid escape \T. This one can be repaired with Fix automatically.
Where it comes from: Windows paths written with single backslashes. In JSON a backslash starts an escape sequence, so C:\Temp is read as \T, which does not exist.
Broken:
{"log": "C:\Temp\logs\app.log"}
Fixed:
{"log": "C:\\Temp\\logs\\app.log"}
\b, \f, \n, \r, \t and \u are valid escapes, so "C:\bin" parses without any error and becomes C: + backspace + in. The file is valid JSON with a broken path, and no validator can catch it, the formatter included. Always double every backslash, or use forward slashes, which Windows accepts in most paths.
ConvertTo-Json in PowerShell and json.dumps in Python escape backslashes for you. Writing paths through them instead of by hand avoids the problem entirely.
Open this example in the JSON formatter
Numbers and special values
Invalid number
zaur.it shows: number with a leading zero, hexadecimal number, plus sign before a number, number starts with a decimal point, or exponent without digits.
Where it comes from: ports, IDs and codes typed with leading zeros (0443, 00123), flags copied from registry exports in hex (0x1F), or numbers written the way a calculator shows them (+1, .5).
Broken:
{"port": 0443, "flags": 0x1F, "ratio": .5}
Fixed:
{"port": 443, "flags": 31, "ratio": 0.5}
If the leading zeros are part of the value, such as an employee number or a site code, it is not a number: store it as a string, "00123". See the table above for how PowerShell and jq silently reinterpret these numbers.
Open this example in the JSON formatter
NaN, Infinity or undefined
zaur.it shows: NaN is not a JSON value.
Where it comes from: Python json.dumps(), which writes NaN and Infinity by default, and JavaScript objects with undefined values. Python also reads NaN back, so Python-to-Python works and the file fails everywhere else.
Broken:
{"cpu_avg": NaN, "limit": Infinity}
Fixed:
{"cpu_avg": null, "limit": null}
In Python, pass allow_nan=False to json.dumps() to get an error at write time instead of a bad file.
Open this example in the JSON formatter
Python True, False or None
zaur.it shows: Python literal True. This one can be repaired with Fix automatically.
Where it comes from: a Python dictionary printed with print() or converted with str(). The output looks like JSON but uses Python spelling.
Broken:
{"enabled": True, "owner": None}
Fixed:
{"enabled": true, "owner": null}
Use json.dumps(data, indent=2) whenever the output is meant to be JSON.
Open this example in the JSON formatter
PowerShell hashtable
zaur.it shows: PowerShell hashtable, not JSON.
Where it comes from: a hashtable literal copied from a script, or the output of a hashtable printed to the console, pasted where JSON was expected.
Broken:
@{ Name = "sql01"; Port = 1433 }
Fixed:
{"Name": "sql01", "Port": 1433}
Let PowerShell do the conversion:
@{ Name = "sql01"; Port = 1433 } | ConvertTo-Json
# For nested objects raise -Depth: the default of 2 truncates deeper levels
$config | ConvertTo-Json -Depth 10
Open this example in the JSON formatter
Invisible characters, encoding and comments
Byte order mark (BOM)
zaur.it shows: invisible byte order mark (U+FEFF).
Where it comes from: a file saved as "UTF-8 with BOM": Windows PowerShell 5.1 Out-File and Set-Content -Encoding UTF8 always add one, and so did older versions of Notepad. The BOM is invisible in every editor. Inside a file it usually appears where two such files were joined, for example with Get-Content a.json, b.json.
Broken:
[
{"name": "sql01"},
{"name": "sql02"}
]
Fixed:
[
{"name": "sql01"},
{"name": "sql02"}
]
Unexpected UTF-8 BOM (decode using utf-8-sig), and so do many Linux tools and web applications. If a file validates here but fails in Python, check the encoding in your editor: it should say UTF-8, not UTF-8 with BOM.
Write JSON files without a BOM:
# PowerShell 7: utf8NoBOM is the default, but be explicit in scripts
$json | Set-Content -Path .\config.json -Encoding utf8NoBOM
# Windows PowerShell 5.1: -Encoding UTF8 always writes a BOM, so use .NET
[IO.File]::WriteAllText("C:\bat\config.json", $json, (New-Object Text.UTF8Encoding $false))
Open this example in the JSON formatter
Invisible space
zaur.it shows: invisible non-breaking space (U+00A0), or another invisible character named with its Unicode code.
Where it comes from: JSON copied from a web page, a wiki, Teams or Confluence, where a normal space was stored as a non-breaking space or a zero-width space. The text looks identical; the parser sees an unknown character.
Broken:
{"name": "sql01"}
Fixed:
{"name": "sql01"}
Use Go to error in the formatter to jump to the character, delete it and type a normal space.
Open this example in the JSON formatter
Comments
zaur.it shows: comment (//) or comment (/*). This one can be repaired with Fix automatically.
Where it comes from: configuration files in the JSONC dialect, which allows comments: VS Code settings.json, Windows Terminal settings.json, tsconfig.json. .NET appsettings.json also tolerates comments. Copied into a system that expects standard JSON, the comments break it.
Broken:
{
// primary SQL node
"name": "sql01"
}
Fixed:
{
"name": "sql01"
}
"_comment": "primary SQL node".
Open this example in the JSON formatter
How to stop producing broken JSON
- Generate, do not type. Build the object in PowerShell or Python and let
ConvertTo-Jsonorjson.dumps()write it. Quotes, commas, escaping and backslashes come out right every time. - Raise the depth in PowerShell.
ConvertTo-Jsonstops at depth 2 by default and flattens anything deeper into strings. Use-Depth 10or more for nested configuration. - Validate with a strict reader. In PowerShell use
Test-Json, notConvertFrom-Json. In pipelines and on Linux,jq -e . file.json > /dev/nullfails the step on invalid input. - Write UTF-8 without a BOM. Use
-Encoding utf8NoBOMin PowerShell 7, or the .NET call shown in the BOM section in Windows PowerShell 5.1. - Keep JSON out of chat and documents. Send it as a file or in a code block so autocorrect cannot replace quotes and spaces.
- Store codes as strings. Anything with meaningful leading zeros, such as employee numbers, site codes or ZIP codes, belongs in quotes.
Related tools
- JSON formatter and validator - paste the file to get the exact line and column, a hint, and automatic repair for the safe cases on this page.
- JWT decoder - the header and payload of a token are JSON; a decoded payload that will not parse usually points at a truncated token.
- Base64 encoder and decoder - decode Base64-wrapped JSON from Kubernetes secrets or API fields before validating it.
Related guides
- How to upgrade PowerShell 7 on Windows 10 and 11 -
Test-Jsonand theutf8NoBOMdefault used on this page come with PowerShell 7. - Base64 encoding explained - why JSON often travels Base64-encoded inside tokens, secrets and API payloads.