# TypeError: “Converting circular structure to JSON”

> TypeError: Converting circular structure to JSON. Send only the fields you need, use util.inspect for logs, a replacer for cycles, or structuredClone to copy.

Canonical: https://app369.com/fix/converting-circular-structure-to-json/
Last updated: 2026-11-08

JSON.stringify(), res.json() or a logger fails with TypeError: Converting circular structure to JSON, often followed by --> starting at object with constructor 'Socket' (or 'ClientRequest', 'HTMLDivElement', 'FiberNode'). The object points back to itself somewhere inside, and JSON has no way to write that.

**Short answer**

Read the constructor name in the message: it tells you what got into the data. Usually it is a whole request or response object, an Axios error, a DOM element, a React event, or a database document with back-references. Send or store only the plain fields you need instead of the whole object. For logging in Node.js, use console.log or util.inspect, which handle cycles. If you really need to serialize a cyclic object, pass a replacer that skips repeated references.

## **Why the object is circular, and the fix**

1. 01 ### **A framework object got into your data**
  > “The JSON format per se doesn't support object references (although an IETF draft exists), hence JSON.stringify() doesn't try to solve them and fails accordingly.” [**MDN, TypeError: cyclic object value**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value) Express req and res, Node.js sockets, Axios error.request and error.response objects, DOM nodes and React events all link back to their parents. Passing one to res.json(), localStorage or a state store fails. Pick the fields you need.```
// instead of res.json({ error: err })
res.status(502).json({
  message: err.message,
  status: err.response?.status,
  data: err.response?.data,
});
```
2. 02 ### **Logging with JSON.stringify** JSON.stringify is a poor logging tool. In Node.js, console.log and util.inspect print cycles as [Circular *1] instead of throwing.```
import { inspect } from 'node:util';
console.log(inspect(obj, { depth: 4 }));
```
3. 03 ### **Your own data links parent and child**
  > “value contains a circular reference.” [**MDN, JSON.stringify(): exceptions**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) Trees with parent pointers, graphs and ORM documents with back-references are circular by design. Serialize a version without the back-links, or use a replacer that drops repeated references.```
function safeStringify(value) {
  const seen = new WeakSet();
  return JSON.stringify(value, (key, val) => {
    if (typeof val === 'object' && val !== null) {
      if (seen.has(val)) return '[Circular]';
      seen.add(val);
    }
    return val;
  });
}
```
4. 04 ### **Copying an object with JSON.parse(JSON.stringify())** This old deep-copy trick fails on cycles, turns dates into strings and Maps into {}, and drops undefined. structuredClone() copies circular objects correctly (it throws on functions and DOM nodes), in browsers and Node.js 17 and later.```
const copy = structuredClone(original);
```

Checked against the vendor’s docs on November 8, 2026: [MDN: TypeError: cyclic object value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value); [MDN: JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**“Maximum call stack size exceeded”**](https://app369.com/fix/maximum-call-stack-size-exceeded/) · [**“Unexpected end of JSON input”**](https://app369.com/fix/unexpected-end-of-json-input/) · [**Axios “Network Error”**](https://app369.com/fix/axios-network-error/)

Questions

## **More on this error**

<details>

<summary>**Does the [Circular] replacer lose data? **+</summary>

It drops the repeated reference, and the simple WeakSet version also marks objects that appear twice without a real cycle. For logs that is fine; for data you will read back, send an explicit plain shape instead.

</details>

<details>

<summary>**Why does this happen with Mongoose or Prisma results? **+</summary>

A cycle with Mongoose usually comes from populated documents that point at each other, or from putting a whole document inside another object. Use .lean() or .toObject() to get plain data, then drop the back-references. Prisma results are plain objects, so a cycle there usually comes from data you attached yourself.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)