RecursionError

Fix Python RecursionError in JSON Serialization

Python's RecursionError during json.dump usually means circular references. Here's how to spot them and fix your code fast.

You're calling json.dumps(your_object) and Python throws RecursionError: maximum recursion depth exceeded. This usually hits when you have a nested structure that loops back on itself — say, a Person object with a manager attribute, and that manager has a direct_report pointing back to the first person. Or a Node class with a parent and children list that creates a cycle. I've seen it a hundred times in real codebases, especially with ORM models (SQLAlchemy, Django) where relationships are bidirectional by default.

The root cause is simple: Python's default JSON encoder walks your object graph recursively, and when it hits a cycle, it keeps going until it blows the recursion limit (usually 1000). It's not a bug in your data — it's the encoder not knowing when to stop.

Step 1: Confirm the cycle

Before touching code, verify it's a circular reference. Try this on your object:

import sys
print(sys.getrecursionlimit())  # usually 1000

If your object is deeply nested (list of lists of lists... 1000 layers deep), that's the culprit. But more often it's a cycle. You can trace it by writing a small function that walks the object and prints keys — but honestly, just inspect your classes. Look for attributes that reference back to the same instance or to a parent that references you.

Step 2: Break the cycle (the real fix)

The cleanest solution is to exclude the back-reference when serializing. You have a few options:

Option A: Use a custom encoder

Override default() in a json.JSONEncoder subclass and skip attributes that create cycles. Here's a generic one I use:

import json

class SafeEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, '__dict__'):
            # Skip attributes that point back to the same object or to a parent
            return {k: v for k, v in obj.__dict__.items()
                    if not isinstance(v, type(obj)) and not isinstance(v, list)}
        return str(obj)

This is blunt — it skips any list attribute (which often contains children) and any attribute of the same type. Tune it to your needs. For a Person with a manager, you'd skip manager or store only the ID.

Option B: Clean up before serializing

If you control the input, strip the back-references before calling json.dumps. For example:

def to_serializable(person):
    return {
        'name': person.name,
        'manager_id': person.manager.id if person.manager else None
    }

This is the most predictable approach — no magic, just explicit data shaping.

Step 3: Use a library that handles cycles

If you can't restructure your objects, try python-json-tricks or blinker? Actually, the best is jsonpickle — it handles circular references out of the box by storing references as keys. Just be aware the output is not standard JSON, it's a special format. For debugging, it's great.

pip install jsonpickle
import jsonpickle
jsonpickle.encode(your_object)

Step 4: Increase recursion limit (temporary fix)

If you're absolutely sure the structure is acyclic but deeply nested, you can bump the limit:

import sys
sys.setrecursionlimit(10000)

But careful — this can crash your Python process with a segfault if you set it too high (above ~100000 on CPython), and it's a band-aid. I'd only use this for quick debugging, not production.

If it still fails

Check these:

  • Did you actually apply the encoder? json.dumps(obj, cls=SafeEncoder) — easy to forget.
  • Is the cycle inside a list or dict? My generic encoder above skips lists, but if your cycle is through a dict value, you need to handle that too. You might need to track visited object ids in the encoder.
  • Are you serializing a generator or a custom iterator? Those also cause recursion errors sometimes — convert to a list first.
  • If you're using SQLAlchemy, check for lazy-loaded relationships that trigger during serialization — that's a different beast. Use marshmallow or Pydantic to control output.

Remember, the RecursionError isn't random — it's your data telling you it has a loop. Find the loop and break it, and you'll never see this error again.

Small note: if you're serializing to send over an API, you probably don't want the entire object graph anyway. Design a DTO (Data Transfer Object) that only has the fields you need.

I've fixed this error more times than I can count, and 90% of the time it's a circular relationship in an ORM model. Skip the recursion limit hack — fix the data structure.

Related Errors in Programming & Dev Tools
0X401B00EC Fix STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST (0x401B00EC) non-fast-forward updates were rejected Git push rejected: non-fast-forward updates fix 0XC00D10B0 Fix NS_E_WMPCORE_MISMATCHED_RUNTIME 0XC00D10B0 Fast 0XC000014A Fix EXCEPTION 0XC000014A Fast — The Real Culprit

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.