{"record":{"id":"53cd5d5faefcbdc4","repo":"withastro/astro","slug":"expected-a-matching-import-for-component-tagnam","errorCode":null,"errorMessage":"Expected a matching import for component `${tagName}`. Did you forget to import it?","messagePattern":"Expected a matching import for component `(.+?)`\\. Did you forget to import it\\?","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/mdx/src/satteri/hast-astro-metadata.ts","lineNumber":104,"sourceCode":"\t}\n}\n\nfunction processJsxNode(\n\tnode: MdxJsxHastNode,\n\tctx: HastVisitorContext,\n\timports: Map<string, Set<ImportSpecifier>>,\n\tfilePath: string,\n) {\n\tconst tagName = node.name;\n\tif (!tagName || !isComponent(tagName)) return;\n\n\tconst hasClient = hasDirective(node, 'client:');\n\tconst hasServerDefer = !hasClient && hasDirective(node, 'server:defer');\n\tif (!hasClient && !hasServerDefer) return;\n\n\tconst matchedImport = findMatchingImport(tagName, imports);\n\tif (!matchedImport) {\n\t\tthrow new Error(\n\t\t\t`Expected a matching import for component \\`${tagName}\\`. Did you forget to import it?`,\n\t\t);\n\t}\n\n\tif (matchedImport.path.endsWith('.astro') && hasClient) {\n\t\tlet clientAttr = 'client:*';\n\t\tfor (const a of node.attributes) {\n\t\t\tif (a.type === 'mdxJsxAttribute' && a.name.startsWith('client:')) {\n\t\t\t\tclientAttr = a.name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tconsole.warn(\n\t\t\t`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.`,\n\t\t);\n\t}\n\n\tconst resolvedPath = resolvePath(matchedImport.path, filePath);","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/integrations/mdx/src/satteri/hast-astro-metadata.ts#L86-L122","documentation":"The hast-astro-metadata pass (in the mdx integration's satteri module) collects island metadata for MDX builds: every component element carrying a `client:` directive or `server:defer` must match an import specifier so its module can be located for hydration/defer metadata. When `findMatchingImport` returns nothing, it throws with the tag name and a hint about the missing import. It is the metadata-collection sibling of the NoMatchingImport error.","triggerScenarios":"An .mdx file using `<Widget client:visible />` or `<Widget server:defer />` where no import named Widget exists, or the imported name differs from the tag.","commonSituations":"Omitting imports when copying component examples into MDX; using `server:defer` on a component that was never imported; renaming an import without updating its usages.","solutions":["Import the component in the same .mdx file with a name matching the tag.","Verify the import specifier is not named-vs-default mismatched (import the default export under the tag's name).","Drop the directive if the tag is plain HTML or should not hydrate/defer.","Note `server:defer` components are also subject to this check — import them too."],"exampleFix":"import Hero from '../../components/Hero';\n\n<Hero server:defer />","handlingStrategy":"validation","validationCode":"// CI check: components used with client:* OR server:defer in MDX must be imported\nimport { globSync } from 'glob';\nimport fs from 'node:fs';\nconst importRe = /import\\s+([A-Za-z_$][\\w$]*)\\s+from\\s+['\"][^'\"]+['\"]/g;\nconst tagRe = /<([A-Z][\\w.]*)[^>]*?\\s(?:client:[a-z]+|server:defer)/g;\nfor (const f of globSync('src/**/*.mdx')) {\n  const src = fs.readFileSync(f, 'utf8');\n  const imported = new Set([...src.matchAll(importRe)].map((m) => m[1]));\n  for (const m of src.matchAll(tagRe)) {\n    if (!imported.has(m[1])) throw new Error(`${f}: <${m[1]}> used with client:*/server:defer without an import`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Import every component that carries client:* or server:defer — both directives are checked.","Match the import specifier name to the JSX tag exactly.","Enforce with an MDX lint in CI so omissions fail before the compiler does."],"tags":["mdx","islands","server-defer","client-directive","imports"],"backgroundTag":"mdx-missing-import","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}