json

FormatValidateConvert

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 Error

Do

  1. Paste the input into the validator.
  2. Press Repair in the editor band.

Result

Nothing here could be repaired automatically.

Try it in the validator →

What each runtime prints for this input
RuntimeMessage
Chrome 153 · Node.js 26Unexpected token 'I', "Internal S"... is not valid JSON
Node.js 18 (older V8)Unexpected token I in JSON at position 0
Firefox 156JSON.parse: unexpected character at line 1 column 1 of the JSON data
Safari 26JSON Parse error: Unexpected identifier "Internal"
Python 3.14 jsonExpecting value: line 1 column 1 (char 0)
This siteUnexpected "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]))
    raise

repr 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 messageRead this page
Expecting valueUnexpected token < in JSON at position 0 · Unexpected end of JSON input · JSON.parse: unexpected character in Firefox
Expecting property name enclosed in double quotesExpected property name or '}' in JSON
Expecting ',' delimiterExpected ',' or '}' after property value in JSON
Invalid control character atBad control character in string literal
Unterminated string starting atUnterminated string in JSON
Illegal trailing comma before end of objectExpected 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.