withastro/astro · error · Error
Cyclic reference detected while serializing props for <${met
Error message
Cyclic reference detected while serializing props for <${metadata.displayName} client:${metadata.hydrate}>!
Cyclic references cannot be safely serialized for client-side usage. Please remove the cyclic reference. What it means
While serializing component props for an island (`serializeArray`), the array was already present in the `parents` WeakSet — i.e. the array is reachable from itself, forming a cycle. JSON serialization cannot represent cycles, and the client hydration payload would be infinite, so Astro throws. The message names the component (`displayName`) and its hydration directive.
Source
Thrown at packages/astro/src/runtime/server/serialize.ts:25
RegExp: 2,
Date: 3,
Map: 4,
Set: 5,
BigInt: 6,
URL: 7,
Uint8Array: 8,
Uint16Array: 9,
Uint32Array: 10,
Infinity: 11,
};
function serializeArray(
value: any[],
metadata: AstroComponentMetadata | Record<string, any> = {},
parents = new WeakSet<any>(),
): any[] {
if (parents.has(value)) {
throw new Error(`Cyclic reference detected while serializing props for <${metadata.displayName} client:${metadata.hydrate}>!
Cyclic references cannot be safely serialized for client-side usage. Please remove the cyclic reference.`);
}
parents.add(value);
const serialized = value.map((v) => {
return convertToSerializedForm(v, metadata, parents);
});
parents.delete(value);
return serialized;
}
function serializeObject(
value: Record<any, any>,
metadata: AstroComponentMetadata | Record<string, any> = {},
parents = new WeakSet<any>(),
): Record<any, any> {
if (parents.has(value)) {
throw new Error(`Cyclic reference detected while serializing props for <${metadata.displayName} client:${metadata.hydrate}>!View on GitHub (pinned to d081033d5f)
Solutions
- Break the cycle before passing the value: map the data to a flat, acyclic structure (e.g. strip parent pointers).
- Use `structuredClone` won't help — clone the data into plain JSON-safe form instead.
- Pass only the serializable subset of data the client actually needs.
Example fix
// before — node has a back-reference to its parent array
const items = [{ id: 1 }];
items[0].parent = items;
<Tree client:load nodes={items} /> // cyclic -> throws
// after — flatten to acyclic data
const items = [{ id: 1, parentId: null }];
<Tree client:load nodes={items} /> Defensive patterns
Strategy: validation
Validate before calling
// Reject cyclic arrays before passing them as island props
function assertAcyclic(value: unknown, seen = new WeakSet()): void {
if (value && typeof value === 'object') {
if (seen.has(value as object)) throw new Error('Cyclic array reference in props');
seen.add(value as object);
if (Array.isArray(value)) value.forEach((v) => assertAcyclic(v, seen));
}
} Type guard
function isAcyclic(value: unknown, seen = new WeakSet()): boolean {
if (value && typeof value === 'object') {
if (seen.has(value as object)) return false;
seen.add(value as object);
if (Array.isArray(value)) return value.every((v) => isAcyclic(v, seen));
}
return true;
} Prevention
- Pass only plain, JSON-safe data to hydrated components.
- Strip parent/back references before rendering.
- Validate complex props with a cycle check in dev builds.
When it happens
Trigger: An array passed as a prop to a hydrated component contains a reference back to itself (directly or transitively); a tree/DOM-like structure with parent pointers passed to `client:*` components; a state object mutated to include a back-reference.
Common situations: Passing a rich data model (graph, tree with parent links, DOM nodes) as a prop; mutable shared state objects that gained circular references before render.
Related errors
- BAD_REQUEST
- ActionsReturnedInvalidDataError
- You tried to add the ${name} client renderer, but its server
- UnsupportedConfigTransformError
- The passed value can't be serialized.
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/6bba5eff02d3580c.
Report an issue: GitHub.