Reputation: 5763
I'm getting an error in my Express app which states:
UnhandledPromiseRejectionWarning: TypeError: Converting circular structure to JSON
I've searched and found references to similar issues, and maybe I'm being a bit slow but I don't even understand what a "circular strcuture" is in JSON. I can't seem to find any relevant information online either as far as explaining what exactly it is and why these types of errors occur. How can a list of photo metadata that I'm retrieving from a third party API contain circular references to itself, JSON is ultimately just a string, how can it reference itself?
Upvotes: 2
Views: 7304
Reputation: 1810
I stumbled across this old question now. I remember having an issue with this some time ago.
There is now a descent documentation on this at MDN - here
I think I found a proposed solution at the time also on MDN, so here is generic simple circular handler that may help some of you. It is in a form of the proposed const/function - circular replacer.
Use it only if you do NOT need to rely on drilling into the objects of the circular references.
Use it like this:
JSON.stringify(obj, jsonCircularReplacer());
For more details read the accompanying comments:
/**
* For safer approach to:
* JSON.stringify(obj);
* or if you experience:
* ERROR TypeError: Converting circular structure to JSON
* you can apply this Circular Replacer
* like this:
* JSON.stringify(obj, jsonCircularReplacer();
* or:
* JSON.stringify(obj, jsonCircularReplacer(replaceCircularsWith)
*
* Note:
* By default, the jsonCircularReplacer,
* replaces circular references and functions with string of:
* "~CIRCULAR~"
* You can adjust this by specifying param: replaceCircularsWith;
* eg:
* JSON.stringify(obj, jsonCircularReplacer('MyCircularReferenceMarker')
*
* Do not use: undefined - that will trigger default,
* but you can use: null if needed
* eg:
* JSON.stringify(obj, jsonCircularReplacer(null)
*
* @param replaceCircularsWith
* @returns
*/
export const jsonCircularReplacer = (replaceCircularsWith: any) => {
const known = new WeakSet();
return (key, value) => {
if ((typeof value === "object" && value !== null) ||
typeof value === "function") {
if (known.has(value)) {
return (replaceCircularsWith !== undefined )
? replaceCircularsWith
: "~CIRCULAR~"
}
known.add(value);
}
return value;
}
}
Similarly, you can also use a simple function (wrapping the above) into:
const myObjectAsString: string = jsonStringifySafe(myObj);
The function is here:
/**
* For safer JSON.stringify alternative.
* If you exprience:
* ERROR TypeError: Converting circular structure to JSON
* You can try this fn instead.
* Note:
* By default, circular references and functions are replaced with string of:
* "~CIRCULAR~"
* You can adjust this by specifying param: replaceCircularsWith;
* (do not use undefined, that will trigger default,
* but you can use: null if needed)
* @param obj
* @param replaceCircularsWith
* @returns
* JSON style string
*/
export function jsonStringifySafe(obj: any, replaceCircularsWith?: any): string {
return JSON.stringify(obj, jsonCircularReplacer(replaceCircularsWith))
}
There are other approaches such as this small utility if you do not mind installing a dependency:
Upvotes: 0
Reputation: 45132
The circular structure you have is not in JSON, but in the object that you are trying to convert to JSON.
Circular structures come from objects which contain something which references the original object. JSON does not have a manner to represent these.
An example would be a collection object where the child objects contain a reference to the parent:
Document
contains a list of Node
s, and each Node
has a reference to its containing Document
. Player
s, who may be carrying one or more Item
s. Each Item
may know it's current owner Player
.Upvotes: 12