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
- ORM / database model instances — when an entity has a
parentorauthorback-reference that points to the root object. - Express.js
reqandresobjects — these contain many internal circular references. Never try to stringify them directly. - DOM nodes stored in JS objects — a DOM node's
parentNodeandchildNodesform a tree with back-pointers. - Event emitter instances — many Node.js EventEmitter-based objects hold internal references that loop back.
- Linked lists and graphs — any data structure where nodes reference each other.
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