JSON Circular Reference Error – Cause and Fix

If you call JSON.stringify() on an object and get TypeError: Converting circular structure to JSON, the object contains a reference loop — somewhere in the data, an object points back to itself. JSON is a tree format; it cannot represent cycles.

What a circular reference looks like

const parent = { name: "parent" };
const child  = { name: "child" };

parent.child = child;
child.parent = parent;  // circular: child points back to parent

JSON.stringify(parent);
// TypeError: Converting circular structure to JSON
//   --> starting at object with constructor 'Object'
//   |     property 'child' -> object with constructor 'Object'
//   --- property 'parent' closes the circle

Common sources of circular references

Fix 1 — remove the back-reference before serializing

The cleanest solution is to not include the circular property in the output at all:

const safeChild = { name: child.name }; // copy only what you need
JSON.stringify({ name: parent.name, child: safeChild }); // works

Fix 2 — use a replacer function to skip seen objects

If you do not know in advance which property is circular, use a replacer that tracks visited objects and replaces any back-reference with a placeholder:

function circularReplacer() {
    const seen = new WeakSet();
    return (key, value) => {
        if (typeof value === 'object' && value !== null) {
            if (seen.has(value)) return '[Circular]';
            seen.add(value);
        }
        return value;
    };
}

JSON.stringify(parent, circularReplacer());
// '{"name":"parent","child":{"name":"child","parent":"[Circular]"}}'

Fix 3 — use a library for full circular serialization

If you need to serialize and then deserialize circular structures (not just log them), use the flatted npm package, which encodes cycles as index references:

import { stringify, parse } from 'flatted';

const json = stringify(parent);   // encodes cycles
const obj  = parse(json);         // restores the circular structure

Note that the output format is not standard JSON — you can only parse it back with flatted.

Serializing only the data you need

In practice, the best fix for API responses is to map your internal objects to plain data transfer objects (DTOs) before serialization. This prevents accidental exposure of internal references and circular structures:

// Internal model
const user = orm.findUser(id); // has circular ORM references

// Safe DTO for the API response
const dto = {
  id: user.id,
  name: user.name,
  email: user.email
};

res.json(dto); // never pass the ORM model directly

Related articles