withastro/astro · error · AstroError
NoClientOnlyHint
NoClientOnlyHint
Error message
Unable to render `${componentName}`. When using the `client:only` hydration strategy, Astro needs a hint to use the correct renderer. What it means
client:only components are never server-rendered, so Astro needs the value of the directive to pick the client renderer. When the value is missing or not a recognized framework name (not in react, preact, vue, svelte, solid-js after alias resolution), NoClientOnlyHint is thrown with a hint listing valid values derived from your probable renderers.
Solutions
- Add the framework value: <Comp client:only="react" /> (or preact, vue, svelte, solid)
- For solid use client:only="solid" (aliased internally to solid-js)
- If using a non-bundled renderer, check its docs for the exact hint string it registers
Example fix
// before <Widget client:only /> // after <Widget client:only="react" />
Defensive patterns
Strategy: validation
Validate before calling
const VALID_HINTS = new Set(['react', 'preact', 'vue', 'svelte', 'solid']);
if (!VALID_HINTS.has(hint)) {
throw new Error('client:only needs one of: ' + [...VALID_HINTS].join(', '));
} Type guard
function isClientOnlyHint(value: unknown): value is string {
return typeof value === 'string' && ['react', 'preact', 'vue', 'svelte', 'solid'].includes(value);
} Prevention
- Always write the framework value: client:only="react"
- Treat a bare client:only as a lint error in code review
- Update hints when switching frameworks in a project
When it happens
Trigger: A bare <Comp client:only /> or client:only={true}; client:only="alpine" or another unsupported framework string; a typo like client:only="reactt"; using a renderer whose name does not match any known alias.
Common situations: Copying bare client:only from old docs or examples; assuming Astro infers the framework from the file extension (it does not for client:only); switching frameworks and forgetting to update the hint.
Related errors
- Error: invalid hydration directive
- MissingMediaQueryDirective
- NoMatchingRenderer
- NoMatchingImport
- You are attempting to render <
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/0e3c6ffd3d8d99fb.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/runtime/server/render/component.ts:218
: 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('|'),
),
});
}
} else if (typeof Component !== 'string') {
const matchingRenderers = validRenderers.filter((r) =>
probableRendererNames.includes(r.name),
);
const plural = validRenderers.length > 1;
if (matchingRenderers.length === 0) {
throw new AstroError({
...AstroErrorData.NoMatchingRenderer,
message: AstroErrorData.NoMatchingRenderer.message(
metadata.displayName,
metadata?.componentUrl?.split('.').pop(),View on GitHub (pinned to 52e6c34790)