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
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
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, });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 }));03
Your own data links parent and child
“value contains a circular reference.” MDN, JSON.stringify(): exceptions
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; }); }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 : MDN: TypeError: cyclic object value; MDN: JSON.stringify().
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA 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
Related: “Maximum call stack size exceeded” · “Unexpected end of JSON input” · Axios “Network Error”