withastro/astro · error · Error
Cyclic reference detected while serializing props for <
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
Props given to a component with a client:* hydration directive must be serialized into the HTML payload so the component can rehydrate in the browser. During array serialization Astro tracks already-visited objects with a WeakSet; if an array contains itself (directly or through a nested value), serialization aborts with this cyclic-reference error because such a structure has no JSON representation. The component name and directive in the message identify exactly which props are affected.
Solutions
- Remove the cycle before passing props — clone into plain data and drop back-references (e.g. delete node.parent)
- Map the structure to a serializable DTO (ids instead of object references) and rebuild relationships on the client
- If the cyclic data is only needed during SSR, remove the client:* directive so props are never serialized
Example fix
---
// before
const items = ['a', 'b'];
items.push(items); // cyclic!
---
<Counter items={items} client:load />
---
// after
---
<Counter items={['a', 'b']} client:load /> Defensive patterns
Strategy: validation
Validate before calling
function hasCycle(value: unknown, path: WeakSet<object> = new WeakSet()): boolean {
if (value === null || typeof value !== 'object') return false;
if (path.has(value as object)) return true;
path.add(value as object);
const cyclic = (Array.isArray(value) ? value : Object.values(value)).some((v) => hasCycle(v, path));
path.delete(value as object);
return cyclic;
}
if (hasCycle(items)) {
throw new Error('items contains a cycle — strip back-references before client:* hydration');
} Prevention
- Pass plain serializable data (DTOs with ids) to hydrated components instead of live object graphs
- Strip parent/back pointers when converting trees for props: const toProp = (n) => ({ ...n, parent: undefined, children: n.children.map(toProp) })
- Remember JSON.stringify fails on the same shapes — if it cannot be JSON-stringified, it cannot cross a client:* boundary
When it happens
Trigger: Passing a self-referential array (const a = []; a.push(a)) to a component with client:load/client:visible/etc.; passing a tree or linked structure where a nested array points back to an object that contains it; class instances or ORM models with parent back-references inside an array prop.
Common situations: Category trees with children and parent links; query results with circular relations; state stores that expose self-referencing objects; code that worked when the component rendered server-only and broke after adding a client:* directive.
Related errors
- ActionsReturnedInvalidDataError
- BAD_REQUEST
- Could not render ` `. No matching import has been found for…
- Expected a matching import for component
- PluginContentImportsError
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/6bba5eff02d3580c.
Report an issue: GitHub.
Appendix: 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 52e6c34790)