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

  1. Verify the component is actually exported under that name from its module (named vs default)
  2. Guard dynamic lookups: const C = registry[name] ?? Fallback;
  3. Fix barrel files so the referenced export is re-exported
  4. 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

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


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)