withastro/astro · error · Error

Unable to render ${metadata.displayName}! This component li

Error message

Unable to render ${metadata.displayName}!

This component likely uses ${formatList(probableRendererNames)},
but Astro encountered an error during server-side rendering.

Please ensure that ${metadata.displayName}:
1. Does not unconditionally access browser-specific globals like `window` or `document`.
   If this is unavoidable, use the `client:only` hydration directive.
2. Does not conditionally return `null` or `undefined` when rendered on the server.
3. If using multiple JSX frameworks at the same time (e.g. React + Preact), pass the correct `include`/`exclude` options to integrations.

If you're still stuck, please open an issue on GitHub or join us at https://astro.build/chat.

What it means

The ambiguous-multiple-renderers branch: more than one renderer's name matched the component, so Astro picked one and called its `ssr.renderToStaticMarkup`, but the SSR render itself failed (threw or returned no markup). This is a generic catch-all guiding you to the most common SSR failure causes rather than a specific AstroError code.

Source

Thrown at packages/astro/src/runtime/server/render/component.ts:256

						validRenderers.length,
					),
					hint: AstroErrorData.NoMatchingRenderer.hint(
						formatList(probableRendererNames.map((r) => '`' + r + '`')),
					),
				});
			} else if (matchingRenderers.length === 1) {
				// We already know that renderer.ssr.check() has failed
				// but this will throw a much more descriptive error!
				renderer = matchingRenderers[0];
				({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
					{ result },
					Component,
					propsWithoutTransitionAttributes,
					children,
					metadata,
				));
			} else {
				throw new Error(`Unable to render ${metadata.displayName}!

This component likely uses ${formatList(probableRendererNames)},
but Astro encountered an error during server-side rendering.

Please ensure that ${metadata.displayName}:
1. Does not unconditionally access browser-specific globals like \`window\` or \`document\`.
   If this is unavoidable, use the \`client:only\` hydration directive.
2. Does not conditionally return \`null\` or \`undefined\` when rendered on the server.
3. If using multiple JSX frameworks at the same time (e.g. React + Preact), pass the correct \`include\`/\`exclude\` options to integrations.

If you're still stuck, please open an issue on GitHub or join us at https://astro.build/chat.`);
			}
		}
	} else {
		if (metadata.hydrate === 'only') {
			html = await renderSlotToString(result, slots?.fallback);
		} else {
			const componentRenderStartTime = performance.now();

View on GitHub (pinned to d081033d5f)

Solutions

  1. Guard browser-global access behind `if (typeof window !== 'undefined')` or an `import.meta.env.SSR` check.
  2. Switch the component to `client:only="<framework>"` if it cannot run on the server at all.
  3. Avoid unconditionally returning `null`/`undefined` during SSR.
  4. When using two JSX frameworks together, configure each integration's `include`/`exclude` so components route to the correct renderer.

Example fix

// before — component reads window at render time
export default function Map() {
  const w = window.innerWidth; // throws during SSR
  return <canvas width={w} />;
}

// after — guard, or render client-only
import Map from './Map.tsx';
<Map client:only="react" />
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard browser globals before they're accessed
const isBrowser = typeof window !== 'undefined';
const width = isBrowser ? window.innerWidth : 0;

Type guard

const canSSR = (Comp: unknown): boolean => {
  // best-effort: only SSR components that don't need browser globals at import time
  try { return typeof Comp === 'function'; } catch { return false; }
};

Try / catch

// Sandbox SSR of a risky component and fall back to client:only
let html: string | null = null;
try {
  html = renderToStringSSR(Risky);
} catch (e) {
  // log and skip SSR; render with client:only instead
}

Prevention

When it happens

Trigger: Component unconditionally reads `window`/`document`/`localStorage` during module evaluation or render; the component conditionally returns `null`/`undefined`; multiple JSX integrations (React + Preact) are active and resolving to the wrong one; the framework component throws internally during SSR.

Common situations: Browser-only libraries (charts, maps, editors) imported into an SSR'd component; React/Preact confusion when both are installed; components that render `null` until a client effect runs.

Related errors


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