withastro/astro · error · Error
Unable to render because it is ! Did you forget to import…
Error message
Unable to render ${displayName} because it is ${Component}!
Did you forget to import the component or is it possible there is a typo? What it means
Before server-rendering a framework component, renderFrameworkComponent checks that it received something to render. If Component is falsy and the element does not carry client:only (which skips SSR entirely by design), Astro throws, telling you the component resolved to undefined and suggesting a missing import or typo. This is the framework-component counterpart of the undefined-vnode error in the JSX runtime.
Solutions
- Verify the component is actually exported under that name from its module (named vs default)
- Guard dynamic lookups: const C = registry[name] ?? Fallback;
- Fix barrel files so the referenced export is re-exported
- Note that client:only only defers the failure to the browser; fix the import instead
Example fix
// before
import { Buton } from './Button.jsx';
<Buton client:load />
// after
import { Button } from './Button.jsx';
<Button client:load /> Defensive patterns
Strategy: type-guard
Validate before calling
const Widget = registry[name];
if (!Widget) {
throw new Error('Unknown framework component in registry: ' + name);
}
<Widget client:load /> Type guard
function isRenderableComponent(C: unknown): C is (props: any) => any {
return typeof C === 'function' || (typeof C === 'object' && C !== null);
} Prevention
- Verify the export exists (named vs default) before adding client:* directives
- Provide fallbacks for map/registry-driven components
- Keep barrel files complete when components are added or renamed
When it happens
Trigger: A typo'd named import from a .jsx/.tsx/.vue/.svelte file; a component library export that was renamed or is not exported; const Component = map[name] returning undefined; an undefined value passed as a JSX component in an .astro file.
Common situations: Upgrading a component library that renamed exports; barrel re-export omissions; dynamic component maps (icons, CMS-driven blocks) with missing keys; named/default import confusion.
Related errors
- Unable to render ! This component likely uses , but Astro…
- Unable to render because it contains an undefined…
- GetImageNotUsedOnServer
- ImageNotFound
- NoAdapterInstalledServerIslands
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/af5ee23d8e6e6b5c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/runtime/server/render/component.ts:83
}
const ASTRO_SLOT_EXP = /<\/?astro-slot\b[^>]*>/g;
const ASTRO_STATIC_SLOT_EXP = /<\/?astro-static-slot\b[^>]*>/g;
function removeStaticAstroSlot(html: string, supportsAstroStaticSlot = true) {
const exp = supportsAstroStaticSlot ? ASTRO_STATIC_SLOT_EXP : ASTRO_SLOT_EXP;
return html.replace(exp, '');
}
async function renderFrameworkComponent(
result: SSRResult,
displayName: string,
Component: unknown,
_props: Record<string | number, any>,
slots: any = {},
): Promise<RenderInstance> {
if (!Component && 'client:only' in _props === false) {
throw new Error(
`Unable to render ${displayName} because it is ${Component}!\nDid you forget to import the component or is it possible there is a typo?`,
);
}
const { renderers, clientDirectives } = result;
const metadata: AstroComponentMetadata = {
astroStaticSlot: true,
displayName,
};
const { hydration, isPage, props, propsWithoutTransitionAttributes } = extractDirectives(
_props,
clientDirectives,
);
let html = '';
let attrs: Record<string, string> | undefined = undefined;
if (hydration) {View on GitHub (pinned to 52e6c34790)