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

  1. Remove the cycle before passing props — clone into plain data and drop back-references (e.g. delete node.parent)
  2. Map the structure to a serializable DTO (ids instead of object references) and rebuild relationships on the client
  3. 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

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


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)