withastro/astro · error · AstroError

NoMatchingImport

NoMatchingImport

Error message

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

What it means

`rehype-analyze-astro-metadata` scans MDX for JSX elements that are components with a `client:` (or `server:defer`) directive — i.e. island candidates. It then matches the tag name against imports parsed from the file. If `findMatchingImport(tagName, imports)` returns nothing, it throws `AstroError` with `NoMatchingImport` so the user gets a clear, attributed build error.

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 d081033d5f)

Solutions

  1. Add a static ESM `import` for the component used with `client:*` at the top of the `.mdx` file.
  2. Verify the imported binding name exactly matches the JSX tag name.
  3. If using a member expression, assign it to a capitalized local const and import that.
  4. Remove the `client:` directive if the component is not meant to hydrate.

Example fix

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

<Counter client:load />
Defensive patterns

Strategy: validation

Validate before calling

function componentsWithClientDirectiveHaveImports(tree: any, imports: Map<string, Set<any>>) {
  const missing: string[] = [];
  visit(tree, (n: any) => {
    if (n.type !== 'mdxJsxFlowElement' && n.type !== 'mdxJsxTextElement') return;
    if (!n.name || !/^[A-Z]/.test(n.name)) return;
    const hasClient = n.attributes?.some((a: any) => a.type === 'mdxJsxAttribute' && a.name.startsWith('client:'));
    if (hasClient && !imports.has(n.name)) missing.push(n.name);
  });
  return missing;
}

Type guard

function isImportedComponent(name: string, imports: Map<string, Set<unknown>>): boolean {
  return imports.has(name);
}

Prevention

When it happens

Trigger: Using `<MyComp client:load />` in MDX without a corresponding `import MyComp from '...'`. Typo in the tag name vs the import. Component used via JSX member expression (`<UI.Button />`) that the importer cannot match. Import is dynamic/conditional and not statically visible.

Common situations: Forgot to import a component used with a hydration directive. Renamed an import but not the JSX usage. Mixing default vs named imports incorrectly. Component comes from a re-export the static parser doesn't follow.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/538aa941e788a74e. Report an issue: GitHub.