json.loads

JSON text in, Python objects out — and a JSONDecodeError that tells you the exact line, column and character where the text stopped being JSON.

json functionPython 2.6+Live demo
Common call
json.loads('{"a": 1}')
Returns
{'a': 1} — dict, list, str, int, float, bool or None
Replaces
eval() on data (unsafe) and hand-written parsing
Watch out
Python repr is not JSON: single quotes and True fail
json.loads(ss — The JSON document. bytes are decoded as UTF-8/16/32 (detected automatically).type: str | bytes | bytearray · required, *, clscls — Custom decoder class; the other keyword arguments are passed to it.type: JSONDecoder subclass · default: None=None, object_hookobject_hook — Called with every decoded dict; its return value replaces the dict.type: callable · default: None=None, parse_floatparse_float — Called with the text of every JSON float, e.g. decimal.Decimal for exact decimals.type: callable · default: None=None, parse_intparse_int — Called with the text of every JSON int.type: callable · default: None=None, parse_constantparse_constant — Called with '-Infinity', 'Infinity' or 'NaN' — raise here to reject them.type: callable · default: None=None, object_pairs_hookobject_pairs_hook — Called with the (key, value) pairs of every object, in order — sees duplicate keys. Takes priority over object_hook.type: callable · default: None=None, **kw)
→ dict | list | str | int | float | bool | None

Demo

Live evaluation
Type any JSON document. The result is the Python value — note True, None and the Python quotes.
Try:
Inputs
textstra JSON document
Code
import json
json.loads('{"name": "Ada", "admin": true, "boss": null}')
Result
{'name': 'Ada', 'admin': True, 'boss': None}

The error position counts from 1 for line and column and from 0 for char. For "missing comma" the parser reads the value 1, skips the whitespace after it, then expects , or } — so the error points at column 9, the opening quote of "b": the first character that could not continue the object.

Parameters

NameTypeRequiredDescription
sstr | bytes | bytearrayyesThe JSON document. bytes are decoded as UTF-8/16/32 (detected automatically).
object_hookcallableno (None)Called with every decoded dict; its return value replaces the dict.
object_pairs_hookcallableno (None)Called with the (key, value) pairs of every object, in order — sees duplicate keys. Takes priority over object_hook.
parse_floatcallableno (None)Called with the text of every JSON float, e.g. decimal.Decimal for exact decimals.
parse_intcallableno (None)Called with the text of every JSON int.
parse_constantcallableno (None)Called with '-Infinity', 'Infinity' or 'NaN' — raise here to reject them.
clsJSONDecoder subclassno (None)Custom decoder class; the other keyword arguments are passed to it.

Return value

dict | list | str | int | float | bool | None — The Python value of the JSON document.

Common patterns

Parse or report
JSONDecodeError is a ValueError subclass with the location built in.
import json
try:
    payload = json.loads(body)
except json.JSONDecodeError as e:
    print(f"bad JSON at line {e.lineno}, column {e.colno}: {e.msg}")
Exact decimals for money
Parse floats as Decimal so 19.99 stays 19.99.
import json
from decimal import Decimal
prices = json.loads(text, parse_float=Decimal)
Objects straight into your own type
object_hook builds something other than a dict for every JSON object.
import json
from types import SimpleNamespace
user = json.loads(text, object_hook=lambda d: SimpleNamespace(**d))
user.name

Examples

1. Nested document
import json json.loads('{"user": {"tags": ["a", "b"]}}')['user']['tags']
Returns
['a', 'b']
2. bytes work too
import json json.loads(b'{"ok": true}')
Returns
{'ok': True}
3. Duplicate keys: last one wins
import json json.loads('{"a": 1, "a": 2}')
Returns
{'a': 2}
4. object_pairs_hook sees all pairs
import json json.loads('{"a": 1, "a": 2}', object_pairs_hook=list)
Returns
[('a', 1), ('a', 2)]
5. Decimal instead of float
import json from decimal import Decimal json.loads('{"price": 19.99}', parse_float=Decimal)
Returns
{'price': Decimal('19.99')}
6. NaN and Infinity are accepted
import json json.loads('[NaN, -Infinity]')
Returns
[nan, -inf]
7. A BOM is rejected
import json json.loads('\ufeff{}')
Returns
json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0)

Pitfalls

1. Passing a file name instead of file content
loads parses the string you give it. A path is just text, and "data.json" is not a JSON value.
loads(path)
import json
json.loads('data.json')
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
load(open file)
import json
from pathlib import Path
Path('data.json').write_text('{"ok": true}')
with open('data.json') as f:
    data = json.load(f)
data
{'ok': True}
2. Rejecting NaN you did not expect
Python accepts NaN/Infinity by default, though they are not standard JSON. parse_constant lets you refuse them.
accepted silently
import json
json.loads('{"score": NaN}')
{'score': nan}
parse_constant
import json
def reject(name):
    raise ValueError(f'{name} is not allowed')
json.loads('{"score": NaN}', parse_constant=reject)
ValueError: NaN is not allowed
3. Losing digits in long decimals
JSON floats become Python floats (53-bit). Integers are exact, decimals are not.
float
import json
json.loads('0.1234567890123456789')
0.12345678901234568
parse_float=Decimal
import json
from decimal import Decimal
json.loads('0.1234567890123456789', parse_float=Decimal)
Decimal('0.1234567890123456789')

When to use

Use it
  • You have JSON as a str or bytes (HTTP body, message, database column)
  • Parsing untrusted data — loads never executes code
Reach for something else
  • Reading from a file → json.load(f)
  • Python literals (single quotes, True, None) → ast.literal_eval
  • Text that has trailing data after the JSON → JSONDecoder().raw_decode

Notes

CPython impl
JSONDecoder.decode via the C scanner in Modules/_json.c — its error texts and positions differ in places from the pure-Python fallback in decoder.py
Positions
lineno and colno count from 1; pos counts code points from 0
Exceptions
JSONDecodeError (a ValueError) for bad JSON; TypeError when s is not str/bytes/bytearray

FAQ

JSON object keys must be in double quotes. The usual cause is Python-style text such as {'a': 1} (produced by str() of a dict) or a trailing comma before }. Produce JSON with json.dumps instead of str().