How to Resolve "TypeError: Converting circular structure to JSON" Error in JavaScript
The TypeError: Converting circular structure to JSON is a common error that occurs when you try to serialize a JavaScript object into a JSON string using JSON.stringify(), but the object contains a circular reference.
This guide will explain what a circular reference is, why it breaks JSON.stringify(), and show you the standard solutions for this problem, including how to use a replacer function and when to use a specialized library.
The Core Problem: What is a Circular Structure?
A circular structure (or circular reference) exists when an object has a property that refers back to itself, either directly or indirectly.
Example of problem:
Direct Circular Reference:
let myObject = { name: 'Alice' };
// The `self` property points back to the object itself.
myObject.self = myObject;
// ⛔️ TypeError: Converting circular structure to JSON
JSON.stringify(myObject);
Indirect Circular Reference:
let user = { name: 'Bob' };
let profile = { user: user }; // Profile references user
user.profile = profile; // User now references profile, creating a loop
// ⛔️ TypeError: Converting circular structure to JSON
JSON.stringify(user);
Why this fails: The JSON.stringify() algorithm works by traversing the object's properties. When it encounters a circular reference, it gets stuck in an infinite loop (user -> profile -> user -> profile...), which it cannot resolve. To prevent a crash, it throws the TypeError.
Solution 1 (Debugging): Using a Custom replacer Function
If your goal is to simply inspect or debug the object without the circular parts, you can provide a custom replacer function to JSON.stringify(). This function can detect and filter out circular references.
This solution removes the circular references from the JSON output. The data is not preserved.
Solution: this replacer function keeps track of all the objects it has already seen. If it sees an object more than once, it knows it's a circular reference and returns undefined to exclude it from the output.
function getCircularReplacer() {
let seen = new WeakSet();
return (key, value) => {
// If the value is an object and not null
if (typeof value === 'object' && value !== null) {
// If we've already seen this object, it's a circular reference
if (seen.has(value)) {
return; // Return `undefined` to ignore this property
}
// Otherwise, add the object to our set of seen objects
seen.add(value);
}
return value;
};
}
// Example Usage:
let myObject = { name: 'Alice' };
myObject.self = myObject;
let jsonString = JSON.stringify(myObject, getCircularReplacer());
console.log(jsonString);
Output: (The circular 'self' property is removed)
{"name":"Alice"}
Solution 2 (Serialization): Using a Library like flatted
If you need to serialize the entire structure (including the circular references) and be able to parse it back into its original form, you cannot use standard JSON.stringify(). For this, you need a specialized library.
The flatted library is a popular, lightweight, and fast solution for this. It replaces circular references with string pointers that can be used to reconstruct the original object.
Solution:
- Install the library:
npm install flatted - Use
flatted.stringify()andflatted.parse():import { stringify, parse } from 'flatted';
let myObject = { name: 'Alice' };
myObject.self = myObject;
// 1. Serialize the object with circular references.
let flattedString = stringify(myObject);
console.log(flattedString);
// Output is a special string format, not standard JSON
// 2. Parse it back to reconstruct the original object structure.
let reconstructedObject = parse(flattedString);
console.log(reconstructedObject.self === reconstructedObject);
// Output: true
This is the recommended best practice when you need to preserve the circular structure for later use.
How the replacer Function Works
The JSON.stringify(value, replacer) method accepts an optional replacer function as its second argument.
- This function is called for each key-value pair in the object being serialized.
- Its return value determines what gets included in the final JSON string.
- If it returns a value, that value is used.
- If it returns
undefined, the property is excluded from the output.
Our getCircularReplacer function uses a WeakSet to keep a memory of every object it has encountered. A WeakSet is ideal for this because it doesn't prevent garbage collection.
A Common Pitfall: Unintentional Circular References
This error often appears when working with complex object structures from libraries or frameworks (like DOM elements or database objects) that have internal parent-child references.
- DOM Elements: An HTML element has a
.parentElementproperty, and its parent has a.childrenproperty that points back to the element. Trying toJSON.stringify()a DOM element will almost always cause this error. - API Responses: Some poorly designed APIs might return data with circular references.
Solution: Do not try to stringify complex, non-data objects like DOM elements. Instead, create a new, clean object containing only the specific properties you need, and then stringify that object.
Conclusion
The "Converting circular structure to JSON" error is a protective mechanism to prevent infinite loops during serialization.
- The root cause is an object that refers back to itself, either directly or indirectly.
- If your goal is to debug or inspect the object, use a custom
replacerfunction to filter out the circular references. - If you need to serialize and later deserialize the complete object structure, the recommended best practice is to use a specialized library like
flatted.