danny-avila/LibreChat · error · AgentRunEnvelopeError
${path} contains a circular reference
Error message
${path} contains a circular reference What it means
Thrown by cloneJsonValue when an object inside the payload is revisited while still on its own ancestor chain (tracked via a WeakSet 'ancestors'). A self-referential or mutually-referential object graph cannot be serialized to JSON and would recurse forever, so the clone refuses it. The WeakSet is scoped per top-level clone and entries are deleted on the way back up, so a value appearing in two sibling branches is fine; only a true cycle trips this.
Source
Thrown at packages/api/src/agents/envelope.ts:123
}
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
return value;
}
if (typeof value === 'number') {
if (!Number.isFinite(value)) {
throw new AgentRunEnvelopeError(`${path} must contain only finite numbers`);
}
return value;
}
if (typeof value !== 'object') {
throw new AgentRunEnvelopeError(`${path} contains a non-JSON ${typeof value} value`);
}
if (ancestors.has(value)) {
throw new AgentRunEnvelopeError(`${path} contains a circular reference`);
}
ancestors.add(value);
try {
const symbolKeys = Object.getOwnPropertySymbols(value);
if (symbolKeys.length > 0) {
throw new AgentRunEnvelopeError(`${path} contains symbol keys`);
}
if (Array.isArray(value)) {
const cloned: unknown[] = new Array(value.length);
let clonedItemCount = 0;
for (const key of Object.getOwnPropertyNames(value)) {
if (key === 'length') {
continue;
}
const index = Number(key);View on GitHub (pinned to 5ff282f900)
Solutions
- Follow the path in the message to the first object that closes the cycle.
- Sever the back-reference (delete the parent pointer) or replace the cyclic structure with an acyclic, JSON-friendly shape (e.g. ids instead of object links).
- Run JSON.stringify(payload) locally before calling createAgentRunEnvelope; if it throws 'circular', fix the shape there first.
Example fix
// before
const node = { id: 1, label: 'root' };
node.parent = node;
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { tree: node } });
// after
const node = { id: 1, label: 'root', parentId: null };
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { tree: node } }); Defensive patterns
Strategy: validation
Validate before calling
function isAcyclic(value: unknown, seen = new WeakSet()): boolean {
if (typeof value !== 'object' || value === null) return true;
if (seen.has(value as object)) return false;
seen.add(value as object);
if (Array.isArray(value)) return (value as unknown[]).every((v) => isAcyclic(v, seen));
return Object.values(value).every((v) => isAcyclic(v, seen));
}
if (!isAcyclic(payload)) throw new Error('payload contains a cycle'); Type guard
function isAcyclicJson(value: unknown, seen = new WeakSet()): boolean {
if (value === null || typeof value !== 'object') return true;
if (seen.has(value as object)) return false;
seen.add(value as object);
const vals = Array.isArray(value) ? value : Object.values(value);
return vals.every((v) => isAcyclicJson(v, seen));
} Try / catch
try {
const env = createAgentRunEnvelope(input);
} catch (e) {
if (e instanceof AgentRunEnvelopeError && /circular reference/.test(e.message)) {
// the path names the cycle origin; sever that back-reference and retry
} else throw e;
} Prevention
- Prefer id references over object back-pointers in payload shapes.
- Validate payloads with JSON.stringify in unit tests; a thrown 'Converting circular structure' fails the test before runtime.
- Avoid reusing long-lived memoized request objects that may be mutated to form cycles.
When it happens
Trigger: A payload object assigned to itself (a.self = a), two objects referencing each other (a.b = b; b.a = a), or a tree node whose parent pointer re-enters the graph.
Common situations: Reusing a memoized request object that was mutated to point back at a parent; passing a DOM-like or AST node tree with parent links into the agent payload; building a graph cache and accidentally embedding it.
Related errors
- ${path} contains a non-JSON ${typeof value} value
- ${path} contains symbol keys
- ${path} contains non-index array properties
- ${path}[${index}] must not be an accessor property
- ${path} contains sparse array entries
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/a24f7c1b24cd63b9.
Report an issue: GitHub.