withastro/astro · warning

You are attempting to render <${displayName} ${prop} />, but

Error message

You are attempting to render <${displayName} ${prop} />, but ${displayName} is an Astro component. Astro components do not render in the client and should not have a hydration directive. Please use a framework component for client rendering.

What it means

Before rendering an .astro component instance, validateComponentProps checks whether any prop name equals a known client:* directive (built from the resolved clientDirectives map). Astro components are server-rendered only — they produce HTML with no client runtime — so a hydration directive on them can never work, and Astro warns at render time while ignoring the prop.

Source

Thrown at packages/astro/src/runtime/server/render/astro/instance.ts:106

		if (isHeadAndContent(returnValue)) {
			return returnValue.content.render(destination);
		} else {
			return renderChild(destination, returnValue);
		}
	}
}

// Issue warnings for invalid props for Astro components
function validateComponentProps(
	props: ComponentProps,
	clientDirectives: SSRResult['clientDirectives'],
	displayName: string,
) {
	if (props != null) {
		const directives = [...clientDirectives.keys()].map((directive) => `client:${directive}`);
		for (const prop of Object.keys(props)) {
			if (directives.includes(prop)) {
				console.warn(
					`You are attempting to render <${displayName} ${prop} />, but ${displayName} is an Astro component. Astro components do not render in the client and should not have a hydration directive. Please use a framework component for client rendering.`,
				);
			}
		}
	}
}

export function createAstroComponentInstance(
	result: SSRResult,
	displayName: string,
	factory: AstroComponentFactory,
	props: ComponentProps,
	slots: any = {},
) {
	validateComponentProps(props, result.clientDirectives, displayName);
	const instance = new AstroComponentInstance(result, props, slots, factory);
	registerIfPropagating(result, factory, instance);
	return instance;

View on GitHub (pinned to 52e6c34790)

Solutions

  1. Remove the client:* prop from the .astro component call site
  2. Split shared props so hydration directives only reach framework (React/Vue/Svelte/Solid) components
  3. If the component needs interactivity, move the interactive part into a framework component and put the client:* directive on that

Example fix

// before
<Card client:load heading="Hello" />

// after
<Card heading="Hello" />
<LikeButton client:load />  <!-- framework component carries the directive -->
Defensive patterns

Strategy: type-guard

Validate before calling

// Attach hydration directives only to framework components
const extra = isAstroFactory(Component) ? {} : { 'client:load': true };
return <Component {...props} {...extra} />;

Type guard

// Mirrors Astro's own marker (packages/astro/src/runtime/server/astro-component.ts sets isAstroComponentFactory = true)
const isAstroFactory = (c: unknown): c is () => any =>
  typeof c === 'function' && (c as { isAstroComponentFactory?: boolean }).isAstroComponentFactory === true;

Prevention

When it happens

Trigger: Rendering an Astro component with a client:load / client:idle / client:visible / client:only / client:media prop — most often via a spread like <Card {...commonProps} /> where the shared props object contains a client directive, or a dynamic component that resolves to a .astro factory at runtime.

Common situations: UI kits where one wrapper spreads the same props into both framework and Astro components; converting a React component to .astro while stale client: attributes remain at call sites; copy-pasting hydration directives from framework usage.

Related errors


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