withastro/astro · error · AstroError

NoMatchingRenderer

NoMatchingRenderer

Error message

Unable to render `${componentName}`.

There are ${validRenderersCount} renderers configured in your `astro.config.mjs` file,
but none were able to server-side render `${componentName}`.

What it means

With client:only="react|preact|vue|svelte|solid(-js)" the hint string is recognized (rendererAliases maps solid to solid-js), but no configured renderer matches it: none of the integrations in astro.config can hydrate that framework, so NoMatchingRenderer is thrown stating how many renderers are configured and hinting at the probable ones. The renderer must be installed and registered even for client:only components.

Solutions

  1. Run npx astro add <framework> (e.g. npx astro add preact) to install and register the matching integration
  2. Verify the integrations array in astro.config.mjs actually includes the renderer for the hinted framework
  3. Restart the dev server after config changes
  4. Alternatively change the hint to a framework you already have installed, if the component supports it

Example fix

// before: astro.config.mjs
integrations: [react()]
// component uses client:only="preact"

// after
import preact from '@astrojs/preact';
integrations: [react(), preact()]
Defensive patterns

Strategy: validation

Validate before calling

// CI check: every client:only hint must have a matching integration
const hints = ['react', 'preact', 'vue', 'svelte', 'solid-js']; // values used in templates
const installed = config.integrations.map((i) => i.name);
for (const h of hints) {
  if (!installed.some((n) => n.includes(h.replace('-js', '')))) {
    throw new Error('client:only="' + h + '" used but its renderer is not in astro.config');
  }
}

Type guard

function hasRendererFor(config: { integrations: { name: string }[] }, framework: string): boolean {
  return config.integrations.some((i) => i.name.includes(framework));
}

Prevention

When it happens

Trigger: client:only="preact" while only @astrojs/react is in integrations; client:only="solid" without @astrojs/solid; the framework package was npm-installed but the Astro integration was never added to astro.config; integrations array assembled conditionally and the branch omitted the renderer.

Common situations: Copy-pasting components between projects with different integrations; manually installing framework deps instead of running astro add; config refactors that dropped an integration; monorepos sharing a config template.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/89c1b562313a7971. Report an issue: GitHub.

Appendix: source

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

		if (!renderer && metadata.hydrateArgs) {
			const rendererName = metadata.hydrateArgs;
			if (typeof rendererName === 'string') {
				renderer = renderers.find(({ name }) => name === rendererName);
			}
		}
	}

	let componentServerRenderEndTime;
	// If no one claimed the renderer
	if (!renderer) {
		if (metadata.hydrate === 'only') {
			const rendererName = rendererAliases.has(metadata.hydrateArgs)
				? rendererAliases.get(metadata.hydrateArgs)
				: metadata.hydrateArgs;
			if (clientOnlyValues.has(rendererName)) {
				// throw an error if provide correct client:only directive but not find the renderer
				const plural = validRenderers.length > 1;
				throw new AstroError({
					...AstroErrorData.NoMatchingRenderer,
					message: AstroErrorData.NoMatchingRenderer.message(
						metadata.displayName,
						metadata?.componentUrl?.split('.').pop(),
						plural,
						validRenderers.length,
					),
					hint: AstroErrorData.NoMatchingRenderer.hint(
						formatList(probableRendererNames.map((r) => '`' + r + '`')),
					),
				});
			} else {
				// throw an error if an invalid hydration directive was provided
				throw new AstroError({
					...AstroErrorData.NoClientOnlyHint,
					message: AstroErrorData.NoClientOnlyHint.message(metadata.displayName),
					hint: AstroErrorData.NoClientOnlyHint.hint(
						probableRendererNames.map((r) => r.replace('@astrojs/', '')).join('|'),

View on GitHub (pinned to 52e6c34790)