withastro/astro · error · AstroError

Could not render `${node.name}`. No matching import has been

Error message

Could not render `${node.name}`. No matching import has been found for `${node.name}`.

What it means

In MDX, hydration directives like `client:load` require the compiler to pair the JSX element with a concrete import so the island's chunk can be built. The rehype-analyze-astro-metadata pass inspects every component element carrying `client:` (or `server:defer`) and looks up `findMatchingImport`; with no import matching the tag name, it throws the core NoMatchingImport AstroError.

Source

Thrown at packages/integrations/mdx/src/rehype-analyze-astro-metadata.ts:49

		const imports = parseImports(tree.children);

		visit(tree, (node) => {
			if (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') return;

			const tagName = node.name;
			if (
				!tagName ||
				!isComponent(tagName) ||
				!(hasClientDirective(node) || hasServerDeferDirective(node))
			)
				return;

			// 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.`,
					);
				}

View on GitHub (pinned to 52e6c34790)

Solutions

  1. Add an explicit ES import for the component at the top of the .mdx file.
  2. Make the imported name match the JSX tag exactly (default import name = tag name).
  3. Remove the `client:` directive if the element is a plain HTML tag, not a component.
  4. Remember Astro components themselves cannot hydrate — if the import resolves to a .astro file you'll get the separate misuse warning; use a framework component for islands.

Example fix

import Counter from '../components/Counter';

<Counter client:load />
Defensive patterns

Strategy: validation

Validate before calling

// CI check: MDX files using client:* components must import them
import { globSync } from 'glob';
import fs from 'node:fs';
const importRe = /import\s+([A-Za-z_$][\w$]*)\s+from\s+['"][^'"]+['"]/g;
const tagRe = /<([A-Z][\w.]*)[^>]*\sclient:[a-z]+/g;
for (const f of globSync('src/**/*.mdx')) {
  const src = fs.readFileSync(f, 'utf8');
  const imported = new Set([...src.matchAll(importRe)].map((m) => m[1]));
  for (const m of src.matchAll(tagRe)) {
    if (!imported.has(m[1])) throw new Error(`${f}: <${m[1]} client:*> used without a matching import`);
  }
}

Prevention

When it happens

Trigger: Writing `<Counter client:load />` in an .mdx file without a corresponding `import Counter from '../components/Counter'`, or with a mismatched imported name.

Common situations: Copy-pasting Astro examples into MDX where the import line was omitted; assuming globally registered components work in MDX; shadowing/renaming imports so the tag no longer matches the specifier.

Related errors


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