withastro/astro · error · AstroError

ReservedSlotName

ReservedSlotName

Error message

Unable to create a slot named `${slotName}`. `${slotName}` is a reserved slot name. Please update the name of this slot.

What it means

At render time Astro wraps a component's slots in a `Slots` instance that exposes each slot name as a boolean property (`slots.has?.('name')` style access). The constructor defines each incoming slot name on the instance, but first rejects any name that already exists as a class member — `has`, `render`, and other prototype methods — because the slot flag would shadow the API. Using one of those names throws `ReservedSlotName`.

Solutions

  1. Rename the slot to something not used by the Slots class (e.g. `renderSlot`, `hasContent`)
  2. Update both the child (`slot="newName"`) and the parent's `<slot name="newName" />`
  3. When wrapping third-party components, check their slot names against the reserved list (`has`, `render`, etc.)

Example fix

<!-- before -->
<Layout slot="render">…</Layout>

<!-- after -->
<Layout slot="main">…</Layout>
<!-- and in Layout.astro: <slot name="main" /> -->
Defensive patterns

Strategy: type-guard

Validate before calling

// Component library: validate slot names before passing them through
const slotsToPass = Object.fromEntries(
  Object.entries(userSlots).filter(([name]) => isSafeSlotName(name)),
);

Type guard

// Slot names must not collide with Slots class members
const RESERVED_SLOT_NAMES = new Set(['has', 'render', 'renderFederated', 'constructor']);
export function isSafeSlotName(name: string): boolean {
  return !RESERVED_SLOT_NAMES.has(name);
}

Prevention

When it happens

Trigger: `<MyComponent slot="render">…</MyComponent>` or `slot="has"`; passing children with those keys programmatically (JSX/MDX named slots); a design system renaming a generic slot to `render` or `has` in a new version, breaking consumers at build/dev render time.

Common situations: Generic wrapper components tempted to call a slot `render`; upgrading a UI library whose slot vocabulary grew into these names; MDX content using `slot` attributes that collide.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/862b2ede65bc75a2. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/core/render/slots.ts:36

		return getFunctionExpression(expression);
	}
	return expression as (...args: any[]) => any;
}

export class Slots {
	#result: SSRResult;
	#slots: ComponentSlots | null;
	#logger: AstroLogger;

	constructor(result: SSRResult, slots: ComponentSlots | null, logger: AstroLogger) {
		this.#result = result;
		this.#slots = slots;
		this.#logger = logger;

		if (slots) {
			for (const key of Object.keys(slots)) {
				if ((this as any)[key] !== undefined) {
					throw new AstroError({
						...AstroErrorData.ReservedSlotName,
						message: AstroErrorData.ReservedSlotName.message(key),
					});
				}
				Object.defineProperty(this, key, {
					get() {
						return true;
					},
					enumerable: true,
				});
			}
		}
	}

	public has(name: string) {
		if (!this.#slots) return false;
		return Boolean(this.#slots[name]);
	}

View on GitHub (pinned to 52e6c34790)