withastro/astro · error · Error
Error: invalid hydration directive
Error message
Error: invalid hydration directive "${key}". Supported hydration methods: ${hydrationMethods} What it means
While extracting directives before SSR of a framework component, Astro validates every client:* attribute against the registered client directives (client:load, client:idle, client:visible, client:media, client:only; client:display-name is special-cased and skipped). An unknown directive name is a hard error listing the supported methods, thrown at render time.
Solutions
- Correct the directive to one of client:load, client:idle, client:visible, client:media, client:only
- If a custom hydration strategy is intended, register it via an integration's clientDirectives hook in astro.config.mjs
- Search the codebase for 'client:' typos (rg 'client:[a-z]+' ) to catch sibling mistakes
Example fix
// before <Counter client:onload /> // after <Counter client:load />
Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = new Set(['load', 'idle', 'visible', 'media', 'only']);
function assertClientDirective(key: string) {
const name = key.split(':')[1];
if (!SUPPORTED.has(name)) {
throw new Error('Unknown hydration directive: client:' + name);
}
} Type guard
function isSupportedDirective(key: string): boolean {
return ['load', 'idle', 'visible', 'media', 'only'].includes(key.split(':')[1] ?? '');
} Prevention
- Memorize the five built-ins: client:load, client:idle, client:visible, client:media, client:only
- Grep for 'client:' to catch typos before build
- Register custom directives via an integration's clientDirectives hook rather than inventing attribute names
When it happens
Trigger: A typo like client:onload, client:visable, or client:scroll on a framework component; a directive name that is not registered because the integration providing it (via its clientDirectives hook) is not installed or not enabled in astro.config; code written for a custom directive whose integration was removed.
Common situations: Typos in directives; copy-pasting examples that rely on a custom client directive from an integration that is not in the project; upgrading and dropping an integration that registered extra directives.
Related errors
- MissingMediaQueryDirective
- NoClientOnlyHint
- NoMatchingImport
- NoMatchingRenderer
- Unable to render because it contains an undefined…
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/826f74c4828f25b7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/runtime/server/hydration.ts:86
}
// This is a special prop added to prove that the client hydration method
// was added statically.
case 'client:component-hydration': {
break;
}
case 'client:display-name': {
break;
}
default: {
extracted.hydration.directive = key.split(':')[1];
extracted.hydration.value = value;
// throw an error if an invalid hydration directive was provided
if (!clientDirectives.has(extracted.hydration.directive)) {
const hydrationMethods = Array.from(clientDirectives.keys())
.map((d) => `client:${d}`)
.join(', ');
throw new Error(
`Error: invalid hydration directive "${key}". Supported hydration methods: ${hydrationMethods}`,
);
}
// throw an error if the query wasn't provided for client:media
if (
extracted.hydration.directive === 'media' &&
typeof extracted.hydration.value !== 'string'
) {
throw new AstroError(AstroErrorData.MissingMediaQueryDirective);
}
break;
}
}
} else {
extracted.props[key] = value;
if (!transitionDirectivesToCopyOnIsland.includes(key)) {View on GitHub (pinned to 52e6c34790)