Concepts / Handling JSON Parsing Errors and Exceptions

Handling JSON Parsing Errors and Exceptions

json.loads() transforms a JSON string into a Python data structure by parsing the text and building corresponding lists, dictionaries, and primitive values.

  • Programming
Interactive lab

Try it: Parsing JSON into Python

How json.loads() reads JSON text token by token and builds Python dicts, lists, strings, numbers, True/False and None, how an access path like data["users"][0]["name"] walks that structure, and what json.dumps() writes back.

How it works

  1. The scanner reads the next token: a brace or bracket, a string in double quotes, a number, true / false / null, or a ',' / ':' delimiter.
  2. '{' starts a Python dict and '[' a list; both are pushed on a parse stack until their closing '}' or ']'.
  3. Inside a dict every key must be a double-quoted string followed by ':' and a value; items are separated by ','.
  4. Anything else stops the parse with JSONDecodeError, reporting the message, line, column and character position.
  5. The access path is applied one subscript at a time: dicts take keys (KeyError if missing), lists take integer indexes (IndexError if out of range).
  6. json.dumps() turns the Python objects back into JSON text (True → true, None → null), optionally indented.

Default run (43 steps): json.loads() receives 105 characters of text. The scanner starts at char 0 and reads one token at a time. … json.dumps(data, indent=2) turns the Python objects back into JSON text (171 characters): True → true, None → null, and strings get double quotes.

Simplified: Written from scratch to match CPython 3.12's json module (messages and positions checked against it); input is limited to 400 characters and 24 nesting levels, and the access path accepts only ["key"] and [index] subscripts. Python 3.13 reports a trailing comma in an object with a different message.

Educational simulation

Loading the simulation…

From Text to Structure

JSON often arrives as text. The function json.loads() reads that JSON string and builds a corresponding Python data structure. The result might contain lists, dictionaries, and primitive values. The original string does not change, so you should assign the returned Python object to a variable before working with it.

python
JSON string[{"id": 1, "name":"Chuck"}]json.loads()parse textlistone dictionarydictionaryid, nameChuckinfo[0]["name"]inputreturnsindex 0key name
What happens to raw JSON text as json.loads() parses it, and how does the resulting structure lead to a nested value?

Tracing Nested User Data

Worked example

Reading the First User's Name

A JSON string represents a list of users. Each user has the fields id, x, and name. How do you reach the first user's name after parsing?

  1. 1
    Parse the string

    Pass the JSON string to json.loads(). The outer square brackets describe a list, so the result is a Python list.

  2. 2
    Select the first item

    Use index 0 to select the first dictionary in the list.

  3. 3
    Select the name field

    Use the key name on that dictionary to reach the user's name value.

Result

The nested access pattern is info[0]['name']. For the generated example below, this produces Chuck.

Code walkthrough
import json

data = '[{"id": 1, "x": 10, "name": "Chuck"}, {"id": 2, "x": 20, "name": "Ada"}]'
info = json.loads(data)

print(type(info).__name__)
print(len(info))
print(info[0])
print(info[0]['name'])
  1. 1
    The outer square brackets in the JSON text represent the list held by info.
  2. 2
    The first curly-braced item becomes the dictionary selected by info[0].
  3. 3
    The name key identifies the value Chuck inside that dictionary.
  • The JSON string is stored in data.
  • json.loads(data) returns a Python list and assigns it to info.
  • len(info) reports two list elements.
  • info[0] selects the first user dictionary.
  • info[0]['name'] selects the name value from that dictionary.
Output
list
2
{'id': 1, 'x': 10, 'name': 'Chuck'}
Chuck
infolistindex 0first useruser dictionaryid, x, namenameChuckselectreturnskey
How do you determine whether a nested value requires a list index, a dictionary key, or both?

JSON and Python Representations

A JSON string and the Python object produced from it are different representations. Before parsing, the data is text. After json.loads() returns, Python has built a new object that can be navigated with Python syntax. The text remains unchanged, while the returned object is the value you inspect and access.

JSON formPython structure after parsing
Object described by curly bracesDictionary
Array described by square bracketsList
JSON string valuePython string value
JSON number valuePython numeric value
JSON boolean or null valuePython primitive value

The source explains that json.loads() builds corresponding lists, dictionaries, and primitive values. The table connects the JSON forms named in the topic to the Python structures created after parsing.

JSON text[{"name": "Chuck"}]Python listdictionary insidejson.loads()
What is the difference between the original JSON text and the Python object created after parsing?

Diagnosing Parse and Access Failures

When parsing fails or the result is not what you expected, trace the operation in stages. First verify that the input is actually a string and contains valid JSON. Next confirm that you understand the structure of the parsed result. Finally check that your field names and indices match that structure. This separates a problem with parsing from a problem with accessing the parsed value.

Input JSONstring to inspectjson.loads()parse textParsed structurelist, dictionary, orprimitiveField accesskey or indexNested valuerequested resultParsing errorinspect inputAccess errorinspect keys and indicessubmitvalid JSONinvalid inputinspectcorrect pathwrong key or index
What happens next when json.loads() cannot parse the input, and how does successful parsing differ from an access error?
  • Common mistake

    Forgetting to import json

    What it looks like

    Calling json.loads(data) without first importing the json module.

    Why it fails

    The name json has not been made available to the program.

    Do this instead

    Import the json module before calling json.loads().

  • Common mistake

    Passing a non-string object to json.loads()

    What it looks like

    Passing an object that is already a Python data structure instead of JSON text.

    Why it fails

    json.loads() is used to parse a JSON string.

    Do this instead

    Verify that the input is a string containing JSON before parsing.

  • Common mistake

    Using a field name that does not exist

    What it looks like

    Trying to access a key that is not present in the parsed dictionary.

    Why it fails

    The access expression does not match the structure represented by the JSON data.

    Do this instead

    Inspect the parsed structure and confirm the exact field names.

  • Common mistake

    Using the wrong navigation order

    What it looks like

    Treating a list as if it were a dictionary or treating a dictionary as if it were a list.

    Why it fails

    The access syntax must match the structure created by parsing.

    Do this instead

    Determine whether each layer is a list or dictionary, then use an index or key accordingly.

Why Documentation Matters

JSON is more concise than XML, but it is also less self-describing. The text contains fewer clues about what each value represents. To navigate a parsed response correctly, you need to know whether the outer structure is a list or dictionary, what each nested item contains, and which keys are available. API documentation provides this expected structure.

JSON responsereceived textAPI documentationexpected structureAccess pathindex and keyparsed shapeexplains
Why must you know the expected JSON structure before choosing a key or index?
EASY

Suppose parsing produces a list whose first element is a dictionary with the key name. Write the access expression that reaches the name value of the first element.

Hints
  • Use index 0 for the first list element.
  • Use the key name for the dictionary field.
  • Combine the two access operations.

What do you think happens?

After parsing a JSON string whose outer value is a list of two user dictionaries, what does len(info) report?

  • 1

  • 2

  • The number of dictionary keys

  • It cannot be determined from the parsed structure

Reveal answer
Answer:

2

The outer square brackets represent a list containing two user dictionaries, so the list has two elements.

A Reliable Parsing Routine

  1. 1
    Confirm that the json module is imported.
  2. 2
    Confirm that the value passed to json.loads() is a string containing JSON.
  3. 3
    Assign the return value of json.loads() to a variable.
  4. 4
    Determine whether the parsed result is organized as a list, dictionary, or another Python value.
  5. 5
    Use list indices and dictionary keys that match the documented structure.
  6. 6
    If an error occurs, inspect each layer step by step to find where your expectation differs from the actual structure.

Key Takeaways

  • json.loads() parses a JSON string and returns a new Python data structure; the original string remains unchanged.
  • The outer JSON shape determines whether the result begins as a Python list, dictionary, or another value.
  • Nested access requires the correct combination of list indices and dictionary keys.
  • JSON is concise but less self-describing, so documentation is important when navigating a response.
  • Debug parsing problems in stages: verify the input, inspect the parsed structure, and then check each access key or index.

Related concepts

More concepts starting with H