Expecting value: line 1 column 1 (char 0)
Python's json module raises this json.decoder.JSONDecodeError when it looks for the start of a value and finds nothing it recognises. At char 0, that happened on the very first character, so the text was either empty or not JSON at all. It is the Python counterpart of Chrome's Unexpected token < and Unexpected end of JSON input rolled into one message.
Input
Internal Server ErrorDo
- Paste the input into the validator.
- Press Repair in the editor band.
Result
Nothing here could be repaired automatically.| Runtime | Message |
|---|---|
| Chrome 153 · Node.js 26 | Unexpected token 'I', "Internal S"... is not valid JSON |
| Node.js 18 (older V8) | Unexpected token I in JSON at position 0 |
| Firefox 156 | JSON.parse: unexpected character at line 1 column 1 of the JSON data |
| Safari 26 | JSON Parse error: Unexpected identifier "Internal" |
| Python 3.14 json | Expecting value: line 1 column 1 (char 0) |
| This site | Unexpected "Internal"line 1, column 1 |
Recorded from each runtime; the wording is in Firefox’s, Safari’s and Python’s sources.
Reading the three numbers
Line and column count from one, while char is an offset into the string that counts from zero, so line 1, column 1 and char 0 all describe the same spot. The exception carries them as attributes too: err.lineno, err.colno and err.pos, next to err.msg for the words and err.doc for the whole text it was given. A column past 1 means the document began well and went wrong later, and the message then names what was expected at that point instead of a value.
What the body really was
Nearly every instance comes from an HTTP call, and the answer is to print what arrived before decoding it:
import json
try:
data = json.loads(body)
except json.JSONDecodeError as err:
print(err.msg, err.lineno, err.colno)
print(repr(body[:200]))
raiserepr matters here, because it shows an empty string as '' and makes invisible characters visible. What it usually reveals:
- An empty body, from a 204 reply, an error status sent with no content, or a file that was never written.
- An HTML page: the address was wrong, a login redirect was followed, or a proxy answered with its own 502 or 504 page.
- Plain text, as in the example: a framework's default error body such as Internal Server Error, or a rate limiter's one-line refusal.
- The wrong variable: a file path, a URL or a response object passed where its text was meant.
With the requests library, check response.status_code and the Content-Type header before calling response.json(), and print response.text[:200] when either is unexpected. The decoder underneath is the same, so the message is too.
A file read twice
One cause has nothing to do with the network. A file object remembers how far it has been read, so after f.read() has consumed the contents, a following json.load(f) reads an empty string and fails with exactly this message at char 0. The same thing happens when a helper function has already read the file you pass it. Read the file once, keep the text, and call json.loads on that, or call f.seek(0) before reading it again.
The exception is a subclass of ValueError, so older code that catches ValueError around a decode still catches this one. Catching it is only half the job, though: log the start of the text alongside it, or the next person to see the error will be back at char 0 with no idea what arrived.
Python's other JSON messages
Python words its errors differently from the browsers, and each wording leads to a page here. This table comes from what Python 3.14 printed for each page's example, with the position removed:
| Python's message | Read this page |
|---|---|
Expecting value | Unexpected token < in JSON at position 0 · Unexpected end of JSON input · JSON.parse: unexpected character in Firefox |
Expecting property name enclosed in double quotes | Expected property name or '}' in JSON |
Expecting ',' delimiter | Expected ',' or '}' after property value in JSON |
Invalid control character at | Bad control character in string literal |
Unterminated string starting at | Unterminated string in JSON |
Illegal trailing comma before end of object | Expected double-quoted property name in JSON |
Unexpected UTF-8 BOM (decode using utf-8-sig) | Unexpected token in JSON from a byte-order mark |
Most of these strings live in CPython's C accelerator for the json module, which is what json.loads uses by default; the byte-order-mark check is in the module's Python half.
Checking it here
If you have the body, paste it into the JSON Validator. Code view underlines the first character it could not read, and the table above shows its message: the parser quotes the word it met, which Python does not. Repair refuses plain text and HTML on purpose, because turning a sentence or a web page into JSON would hide the real failure behind a valid document. The fix belongs in the request, not in the text. For a body that is almost JSON, a Python dictionary printed with single quotes for example, the guide to fixing invalid JSON shows what Repair changes.