JSON errors explained: what each message means and how to fix it

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 withMost likely cause
Expecting valuetrailing comma in an array, extra comma, unquoted text, True / None, PowerShell hashtable, +1 or .5, empty input
Expecting property name enclosed in double quotestrailing comma in an object, single quotes, key without quotes, curly quotes, comment
Expecting ',' delimitermissing comma, unclosed bracket, wrong closing bracket, leading zero or hex number
Expecting ':' delimitermissing colon
Extra datatext after the JSON value
Unterminated string starting atstring never closed
Invalid control character attab or line break inside a string
Invalid \escapebackslash 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 containsMost likely cause
Unexpected token ']'trailing comma in an array
Unexpected token ','extra comma
Expected double-quoted property nametrailing comma before }
Expected property name or '}'single quotes, unquoted key, curly quotes, comment
Expected ',' or '}' after property valuemissing comma, unclosed object, hex number
Expected ',' or ']' after array elementwrong closing bracket
Expected ':' after property namemissing colon
Unexpected end of JSON inputempty or cut-off input
Unexpected non-whitespace character after JSONsecond value or trailing text
Unterminated string in JSONstring never closed
Bad control character in string literaltab or line break in a string
Bad escaped characterbackslash in a path
Unexpected number in JSONnumber with a leading zero
Unexpected token 'N', 'T', '@', 'p'NaN, True, @{ } or @, unquoted word
Unexpected token followed by an invisible characterBOM or non-breaking space

jq

Message containsMost likely cause
Expected another array elementtrailing comma in an array
Expected another key-value pairtrailing comma in an object
Expected value before ','extra comma
Expected separator between valuesmissing comma or missing colon
Unfinished JSON term at EOFunclosed bracket
Objects must consist of key:value pairswrong closing bracket
Invalid numeric literaljq's catch-all for text it cannot read: single quotes, unquoted key, unquoted value, True / None, comment, curly quotes, invisible space
Unfinished string at EOFstring never closed
Invalid string: control characterstab or line break in a string
Invalid escapebackslash 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 containsMost likely cause
After parsing a value an unexpected character was encounteredmissing comma
Invalid character after parsing property name. Expected ':'missing colon
Unexpected end when deserializing objectunclosed bracket
JsonToken EndObject is not valid for closing JsonType Arraywrong closing bracket
Additional text encountered after finished reading JSON contentsecond value or trailing text
Unexpected character encountered while parsing valueunquoted text, True / None, hashtable, @ or $, plus sign
Invalid property identifier charactercurly quotes
Unterminated string. Expected delimiterstring never closed
Bad JSON escape sequencebackslash 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.

SampleChrome / NodePythonjq 1.7PowerShell 7
ConvertFrom-Json
PowerShell 7
Test-Json
Trailing commaRejectedRejectedRejectedAcceptedRejected
Single quotesRejectedRejectedRejectedAcceptedRejected
Key without quotesRejectedRejectedRejectedAcceptedRejected
// commentRejectedRejectedRejectedAcceptedRejected
Tab inside a stringRejectedRejectedRejectedAcceptedRejected
Empty item ["a",,"b"]RejectedRejectedRejectedAccepted, reads it as nullRejected
Leading zero 0443RejectedRejectedAccepted, reads 443Accepted, reads 291Rejected
Hex 0x1FRejectedRejectedRejectedAccepted, reads 31Rejected
NaNRejectedAcceptedAcceptedAcceptedRejected
Common mistake: the leading zero row is a real data bug, not just a syntax issue. PowerShell 7 reads 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
}
Note: every parser reports this error at the start of the next line, because that is where it notices something is wrong. The comma is missing at the end of the line above the reported position.

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"]
}
Warning: PowerShell 7 does not reject this: it turns the empty slot into 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
}
Note: jq accepts empty input and prints nothing, so a script that pipes an empty file into jq succeeds silently. Use 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"}
Common mistake: only some paths fail. \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"}
]
Warning: a BOM at the very start of the file is accepted by the formatter and by browsers, which strip it before parsing. Python rejects it with 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"
}
Note: if the file really is JSONC for an application that supports it, keep the comments there and remove them only in the copy you send elsewhere. To document a setting inside standard JSON, use an extra property such as "_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-Json or json.dumps() write it. Quotes, commas, escaping and backslashes come out right every time.
  • Raise the depth in PowerShell. ConvertTo-Json stops at depth 2 by default and flattens anything deeper into strings. Use -Depth 10 or more for nested configuration.
  • Validate with a strict reader. In PowerShell use Test-Json, not ConvertFrom-Json. In pipelines and on Linux, jq -e . file.json > /dev/null fails the step on invalid input.
  • Write UTF-8 without a BOM. Use -Encoding utf8NoBOM in 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.

  • 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.