withastro/astro · warning
You are attempting to render <${node.name!} ${clientAttribut
Error message
You are attempting to render <${node.name!} ${clientAttribute.name} />, but ${node.name!} 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
While compiling .mdx files, the rehype-analyze-astro-metadata pass resolves each JSX element to its import. When the import path ends in .astro and the element carries any mdxJsxAttribute whose name starts with client:, the compiler warns that Astro components are server-side only — a hydration directive on them cannot work and should be removed or moved to a framework component.
Source
Thrown at packages/integrations/mdx/src/rehype-analyze-astro-metadata.ts:62
// From this point onwards, `node` is confirmed to be an island component
// Match this component with its import source
const matchedImport = findMatchingImport(tagName, imports);
if (!matchedImport) {
throw new AstroError(
AstroErrorData.NoMatchingImport.message(node.name!),
AstroErrorData.NoMatchingImport.hint,
);
}
// If this is an Astro component, that means the `client:` directive is misused as it doesn't
// work on Astro components as it's server-side only. Warn the user about this.
if (matchedImport.path.endsWith('.astro')) {
const clientAttribute = node.attributes.find(
(attr) => attr.type === 'mdxJsxAttribute' && attr.name.startsWith('client:'),
) as MdxJsxAttribute | undefined;
if (clientAttribute) {
console.warn(
`You are attempting to render <${node.name!} ${
clientAttribute.name
} />, but ${node.name!} 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.`,
);
}
}
const resolvedPath = resolvePath(matchedImport.path, file.path);
if (hasClientOnlyDirective(node)) {
// Add this component to the metadata
metadata.clientOnlyComponents.push({
exportName: matchedImport.name,
localName: '',
specifier: tagName,
resolvedPath,
});
// Mutate node with additional island attributesView on GitHub (pinned to 52e6c34790)
Solutions
- Remove the client:* attribute from the .astro component usage
- Extract the interactive part into a framework component (React/Svelte/Vue/Solid) and place the client:* directive on that instead
- Reconsider whether the component needs client JS at all — most .astro components render static HTML
Example fix
# before src/content/docs/guide.mdx import Card from '../../components/Card.astro'; import Like from '../../components/Like.svelte'; <Card client:load title="Hello" /> # after <Card title="Hello"> <Like client:load /> </Card>
Defensive patterns
Strategy: type-guard
Validate before calling
# CI review aid: list every client: directive in MDX content for manual check # against imports — flag ones whose component comes from a .astro file grep -rn --include='*.mdx' 'client:' src/content
Type guard
const isAstroComponentFactory = (c: unknown): c is () => any =>
typeof c === 'function' &&
(c as { isAstroComponentFactory?: boolean }).isAstroComponentFactory === true;
// in dynamic JSX: only attach client:* when the component is NOT an Astro factory
const props = isAstroComponentFactory(Comp) ? rest : { ...rest, 'client:load': true }; Prevention
- In MDX, attach client:* only to framework component imports
- Review every grep hit for `client:` in content PRs
- Keep .astro components presentational; put islands in framework files
When it happens
Trigger: In an .mdx file: `import Card from './Card.astro'` followed by `<Card client:load />` (any client:* attribute). Emitted at compile time, once per offending element, via console.warn during the rehype pass.
Common situations: Docs/content sites authoring in MDX with .astro components; copy-pasting hydration directives from framework component usage; prototyping interactivity by slapping client: on whatever component is at hand.
Related errors
- You are attempting to render <${tagName} ${clientAttr} />, b
- Could not render `${node.name}`. No matching import has been
- You are attempting to render <${displayName} ${prop} />, but
- Expected a matching import for component `${tagName}`. Did y
- [MDX] A remark or rehype plugin attempted to inject invalid
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/5ed53972fd297adf.
Report an issue: GitHub.