karatelabs/karate · error · JsErrorException
Converting circular structure to JSON
Error message
Converting circular structure to JSON
What it means
JSON.stringify detected a circular reference: the same Map/List (object/array) instance appeared twice on the current serialization path (tracked via the `seen` identity set). Since the structure would never terminate, the serializer throws a TypeError('Converting circular structure to JSON').
Solutions
- Break the cycle before serializing (remove/null out back-references).
- Use a replacer that skips known circular keys: `(k, v) => k === 'parent' ? undefined : v`.
- Serialize a projected copy containing only the fields you need.
- If cycles are intentional, switch to a format that supports them or serialize node ids instead of object references.
Example fix
// before
node.parent = tree;
karate.stringify(tree); // cycle
// after
var json = karate.stringify(tree, function(k, v) {
return k === 'parent' ? undefined : v;
}); Defensive patterns
Strategy: validation
Validate before calling
function hasCycle(root) { var seen = new Set(); function walk(v) { if (!(v && typeof v === 'object')) return false; if (seen.has(v)) return true; seen.add(v); return Object.values(v).some(walk); } return walk(root); } Try / catch
try { json = karate.stringify(obj); } catch (e) { if (String(e).indexOf('circular') !== -1) { json = karate.stringify(obj, function(k, v) { return k === 'parent' ? undefined : v; }); } else { throw e; } } Prevention
- Avoid back-references (parent pointers) in objects destined for JSON
- Project to plain DTOs before serializing graph-shaped data
- Use a replacer to drop known cyclic keys
- Keep debug attachments out of serialized payloads
When it happens
Trigger: Serializing objects that reference themselves directly or transitively — e.g. obj.self = obj, parent/child doubly-linked nodes, or JS wrappers holding Java maps that point back.
Common situations: Caching a parent reference on child objects then stringifying the tree; attaching a request object to its own response for debugging; graph-shaped data (linked lists, DOM-like nodes) dumped to JSON.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- Do not know how to serialize a BigInt
- fromJson() needs one argument: a JSON string
- toJson() needs at least one argument
- JS error
- Cannot convert null or undefined to object
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/8e6009fc10d1dacf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsJson.java:187
return Terms.UNDEFINED;
}
if (value instanceof JsValue jv && !(value instanceof JsUndefined)) {
value = jv.getJavaValue(); // Number / String / Boolean / Date wrappers
}
if (value instanceof BigInteger || value instanceof JsBigInt) {
throw JsErrorException.typeError("Do not know how to serialize a BigInt");
}
// §25.5.2.2 SerializeJSONNumber: a finite Number is its ToString, a
// non-finite one is the literal null — JSON has no NaN / Infinity.
// Only here: Terms.numberToString stays the ToString seam String(NaN) shares.
if (value instanceof Number n && !Double.isFinite(n.doubleValue())) {
return null;
}
if (!(value instanceof Map<?, ?>) && !(value instanceof List<?>)) {
return value;
}
if (!seen.add(value)) {
throw JsErrorException.typeError("Converting circular structure to JSON");
}
try {
return value instanceof List<?> list
? serializeArray(context, list, replacerFn, propertyList, seen)
: serializeObject(context, value, replacerFn, propertyList, seen);
} finally {
seen.remove(value);
}
}
private static Object serializeObject(Context context, Object value, JsCallable replacerFn,
List<String> propertyList, Set<Object> seen) {
Map<Object, Object> result;
// a PropertyList always reshapes the object — it selects and reorders keys
boolean changed = propertyList != null;
if (value instanceof JsObject jo) {
// §25.5.2 SerializeJSONProperty does Get(holder, key): accessor
// getters run, and a PropertyList key resolves through theView on GitHub (pinned to a22eb90246)