Uncaught Type Error: cyclic object value (JSON.stringify)*

Loading

Uncaught TypeError: Converting circular structure to JSON (cyclic object value in JSON.stringify)

Overview

The error “Uncaught TypeError: Converting circular structure to JSON” occurs when attempting to use JSON.stringify() on an object that has circular references. A circular reference means that an object contains a reference to itself, either directly or indirectly, creating an infinite loop when trying to convert it to a JSON string.


Understanding JSON.stringify()

JSON.stringify() is a built-in JavaScript method used to convert a JavaScript object into a JSON string. However, JavaScript’s JSON.stringify() does not support circular references because JSON is a tree-structured format, not a graph.

Example of JSON.stringify() in a Simple Object

const obj = {
    name: "John",
    age: 30
};

console.log(JSON.stringify(obj)); 
// Output: {"name":"John","age":30}

This works fine because obj does not have any cyclic references.


What Causes the Circular Structure Error?

A circular reference happens when an object refers to itself within one of its properties, either directly or through a nested structure.

Example of a Circular Reference

let obj = {};
obj.self = obj; // obj contains a reference to itself

console.log(JSON.stringify(obj)); 
// Uncaught TypeError: Converting circular structure to JSON

In this example, obj contains a property self that refers back to obj itself. When JSON.stringify(obj) is called, it goes into an infinite loop because it keeps trying to serialize the self property, which leads back to the object.

Example with an Indirect Circular Reference

let obj1 = {};
let obj2 = { parent: obj1 };
obj1.child = obj2;

console.log(JSON.stringify(obj1)); 
// Uncaught TypeError: Converting circular structure to JSON

Here, obj1 has a child property referring to obj2, while obj2 has a parent property referring back to obj1. This indirect circular reference also results in an error when calling JSON.stringify().


How to Handle Circular References in JSON.stringify()

1. Removing Circular References Manually

If you have control over the object, you can remove circular references before calling JSON.stringify().

let obj = {};
obj.name = "Alice";
obj.self = obj; // Circular reference

delete obj.self; // Remove the circular reference
console.log(JSON.stringify(obj)); // {"name":"Alice"}

In this case, manually deleting the reference allows JSON.stringify() to work correctly.


2. Using a Custom Serializer with a Seen Set

You can use a custom replacer function to track seen objects and prevent circular references from being serialized.

function removeCircularReferences() {
    const seen = new WeakSet();
    return function (key, value) {
        if (typeof value === "object" && value !== null) {
            if (seen.has(value)) {
                return "[Circular]"; // Replace circular references with a placeholder
            }
            seen.add(value);
        }
        return value;
    };
}

let obj = {};
obj.self = obj; // Circular reference

console.log(JSON.stringify(obj, removeCircularReferences()));
// Output: {"self":"[Circular]"}

Here, a WeakSet is used to track visited objects. If an object is encountered again, it replaces it with a "[Circular]" placeholder.


3. Using Third-Party Libraries

Several third-party libraries can handle circular references automatically:

Using flatted (npm package)

Flatted is a lightweight JSON parser that supports circular structures.

npm install flatted
import { stringify, parse } from "flatted";

let obj = {};
obj.self = obj; // Circular reference

console.log(stringify(obj));
// Output: {"self":"~"}

let parsed = parse(stringify(obj));
console.log(parsed.self === parsed); // true (restores the original reference)

Using circular-json

npm install circular-json
const CircularJSON = require("circular-json");

let obj = {};
obj.self = obj; // Circular reference

console.log(CircularJSON.stringify(obj));
// Output: {"self":"[Circular]"}

This library safely serializes circular references and reconstructs them when parsing.


4. Cloning Objects Without Circular References

If you need to clone an object but avoid circular references:

function deepClone(obj, seen = new WeakMap()) {
    if (typeof obj !== "object" || obj === null) {
        return obj;
    }
    if (seen.has(obj)) {
        return "[Circular]";
    }
    let copy = Array.isArray(obj) ? [] : {};
    seen.set(obj, copy);
    for (let key in obj) {
        copy[key] = deepClone(obj[key], seen);
    }
    return copy;
}

let obj = {};
obj.self = obj; // Circular reference

let cloned = deepClone(obj);
console.log(JSON.stringify(cloned));
// Output: {"self":"[Circular]"}

This function recursively clones objects while avoiding circular references.


Common Use Cases Where This Error Occurs

  1. Handling DOM elements with references let div = document.createElement("div"); div.ref = div; // Circular reference console.log(JSON.stringify(div)); // Uncaught TypeError: Converting circular structure to JSON
  2. Logging Circular References in Debugging
    • If you try console.log(JSON.stringify(window)), you’ll get the same error because the window object has circular references.
  3. Working with Data Structures like Trees and Graphs
    • Trees and graphs often have parent-child references, leading to circular references.
  4. Serializing Large Objects with Cross-References let user = { name: "Alice" }; let order = { id: 123, customer: user }; user.lastOrder = order; console.log(JSON.stringify(user)); // Uncaught TypeError: Converting circular structure to JSON

Leave a Reply

Your email address will not be published. Required fields are marked *