github/copilot-sdk · error · ResponseError
cyclic_value
cyclic_value
Error message
${context.label} contains a cyclic reference at ${path} What it means
The strict JSON validator detects cyclic references while walking journaled factory values, using an ancestors set. JSON.stringify throws on cycles ('Converting circular structure to JSON'), so the library rejects them eagerly with the precise path instead of letting serialization fail later and corrupt the journal.
Solutions
- Follow the error's `path` and break the cycle — remove the back-reference or store an id/weak reference instead.
- Serialize with a replacer that drops parent links, or map the structure to a plain JSON shape first.
- For needed relationships, journal ids and rehydrate the graph after replay instead of journaling object references.
Example fix
// before
node.parent = parent; // cycle when journaling node
return { node };
// after
return { node: { ...node, parent: parent ? parent.id : null } }; Defensive patterns
Strategy: validation
Validate before calling
function assertAcyclic(value, seen = new Set(), path = "$") {
if (value && typeof value === "object") {
if (seen.has(value)) throw new Error(`Cycle at ${path}`);
seen.add(value);
if (Array.isArray(value)) value.forEach((v, i) => assertAcyclic(v, seen, `${path}[${i}]`));
else for (const [k, v] of Object.entries(value)) assertAcyclic(v, seen, `${path}.${k}`);
seen.delete(value);
}
} Try / catch
try {
session.runFactory(step);
} catch (e) {
if (e?.details?.category === "cyclic_value") {
console.error(`Break cyclic reference at ${e.details.path}`);
} else throw e;
} Prevention
- Represent parent/child relations with ids, not object back-references.
- Snapshot to plain JSON (JSON.parse(JSON.stringify(...)) with a replacer) before journaling complex graphs.
- Never cache an object inside itself (memo.self = memo).
When it happens
Trigger: Returning a factory result or step value that references itself directly (obj.self = obj) or indirectly (a.parent = a inside arrays/nested objects), e.g. attaching a parent back-reference for navigation.
Common situations: Doubly-linked tree nodes with parent pointers, DOM-like structures, caching an object inside itself, circular imports producing self-referencing module state.
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
- non_finite_number
- negative_zero
- unsupported_type
- unsupported_object
- Unexpected trailing content at position
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/867124b1dedeb747.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:2351
typeof current === "bigint"
) {
throw strictJsonValidationError(
context,
"unsupported_type",
`${context.label} contains a function, symbol, or BigInt at ${path}`,
path
);
}
if (typeof current !== "object") {
throw strictJsonValidationError(
context,
"unsupported_type",
`${context.label} contains a function, symbol, or BigInt at ${path}`,
path
);
}
if (ancestors.has(current)) {
throw strictJsonValidationError(
context,
"cyclic_value",
`${context.label} contains a cyclic reference at ${path}`,
path
);
}
ancestors.add(current);
try {
if (Array.isArray(current)) {
const keys = Reflect.ownKeys(current);
if (
keys.length !== current.length + 1 ||
keys.some(
(key) =>
key !== "length" &&
(typeof key !== "string" ||
!/^(0|[1-9]\d*)$/.test(key) ||View on GitHub (pinned to cd8cf15dc3)