withastro/astro · warning
You are attempting to render <${tagName} ${clientAttr} />, b
Error message
You are attempting to render <${tagName} ${clientAttr} />, but ${tagName} 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
The hast-based counterpart of the MDX metadata analyzer (used when JSX content flows through the markdown/hast pipeline): after matching an element to its import, if the import path ends in .astro and the node carries a client directive (hasClient), it warns that Astro components do not render in the client. The exact attribute name is included when one is found; otherwise the generic client:* placeholder is shown.
Source
Thrown at packages/integrations/mdx/src/satteri/hast-astro-metadata.ts:117
const hasServerDefer = !hasClient && hasDirective(node, 'server:defer');
if (!hasClient && !hasServerDefer) return;
const matchedImport = findMatchingImport(tagName, imports);
if (!matchedImport) {
throw new Error(
`Expected a matching import for component \`${tagName}\`. Did you forget to import it?`,
);
}
if (matchedImport.path.endsWith('.astro') && hasClient) {
let clientAttr = 'client:*';
for (const a of node.attributes) {
if (a.type === 'mdxJsxAttribute' && a.name.startsWith('client:')) {
clientAttr = a.name;
break;
}
}
console.warn(
`You are attempting to render <${tagName} ${clientAttr} />, but ${tagName} 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, filePath);
const exportName =
matchedImport.name === '*' ? tagName.split('.').slice(1).join('.') : matchedImport.name;
const metadata = (ctx.data.__astroMetadata ??= createDefaultAstroMetadata());
if (hasClient && findAttrValue(node, 'client:only') !== null) {
metadata.clientOnlyComponents.push({
exportName: matchedImport.name,
localName: '',
specifier: tagName,
resolvedPath,
});
ctx.setProperty(node, 'client:display-name', tagName);
ctx.setProperty(node, 'client:component-path', resolvedPath);View on GitHub (pinned to 52e6c34790)
Solutions
- Drop the client:* attribute from the .astro component element
- Hydrate a framework component embedded inside (or beside) the Astro component instead
- If the directive was accidental, simply delete it to silence the warning
Example fix
# before src/content/docs/page.mdx import Nav from '../../components/Nav.astro'; <Nav client:visible /> # after import Nav from '../../components/Nav.astro'; import Search from '../../components/Search.svelte'; <Nav> <Search client:visible slot="search" /> </Nav>
Defensive patterns
Strategy: type-guard
Validate before calling
# CI review aid: surface all client: directives in MDX sources; # each hit whose component import ends in .astro is a bug 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;
// branch before attaching hydration props in shared/dynamic components
const hydration = isAstroComponentFactory(Comp) ? {} : { 'client:visible': true }; Prevention
- Attach client:* in MDX only to framework components (React/Svelte/Vue/Solid)
- When migrating a component to .astro, delete leftover client: attributes at every call site
- Run the client: grep as a content-CI check
When it happens
Trigger: An .mdx file (or markdown processed through the hast pipeline) using an imported .astro component with a client:* attribute — e.g. <Nav client:visible /> where Nav resolves to a .astro file. Warned during compilation of the containing file.
Common situations: Same as the rehype variant: docs and content sites in MDX, hydration directives copy-pasted from framework components, components migrated from React/Vue to .astro with leftover client: attributes.
Related errors
- You are attempting to render <${node.name!} ${clientAttribut
- 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/072878b125836280.
Report an issue: GitHub.