livewire/livewire · error · Exception
You must define a "hydrate" method
Error message
You must define a "hydrate" method
What it means
The abstract Synth base class marks only match() as abstract - hydrate() is not defined, so a subclass that omits it gets the call routed through Synth::__call(), which throws on the first hydration. This happens on the request after render: dehydration succeeds, then the snapshot comes back and the synth cannot rebuild the value. It is a developer-error guard against half-implemented synthesizers.
Source
Thrown at src/Mechanisms/HandleComponents/Synthesizers/Synth.php:43
{
return false;
}
function get(&$target, $key) {
if (is_array($target)) {
return $target[$key] ?? null;
}
return $target->$key;
}
function __call($method, $params) {
if ($method === 'dehydrate') {
throw new \Exception('You must define a "dehydrate" method');
}
if ($method === 'hydrate') {
throw new \Exception('You must define a "hydrate" method');
}
if ($method === 'hydrateFromType') {
throw new \Exception('You must define a "hydrateFromType" method');
}
if ($method === 'get') {
throw new \Exception('This synth doesn\'t support getting properties: '.get_class($this));
}
if ($method === 'set') {
throw new \Exception('This synth doesn\'t support setting properties: '.get_class($this));
}
if ($method === 'unset') {
throw new \Exception('This synth doesn\'t support unsetting properties: '.get_class($this));
}
View on GitHub (pinned to 1a3fde34c5)
Solutions
- Define hydrate($value, $meta, $hydrateChild) on the synth that reconstructs the target from the dehydrated data
- If you only need serialization to the client, switch to a one-way approach (computed property or toArray in dehydrate) instead of a synth
- Add a CI test that performs a full round trip (render then update) for components using each custom synth
Example fix
// before - render works, but the next request cannot rebuild the value
class CurrencySynth extends Synth {
public static $key = 'cur';
static function match($target) { return $target instanceof Currency; }
function dehydrate($target, $dehydrateChild) {
return [['amount' => $target->amount, 'code' => $target->code], []];
}
}
// after - hydration added
class CurrencySynth extends Synth {
public static $key = 'cur';
static function match($target) { return $target instanceof Currency; }
function dehydrate($target, $dehydrateChild) {
return [['amount' => $target->amount, 'code' => $target->code], []];
}
function hydrate($value, $meta, $hydrateChild) {
return new Currency($value['amount'], $value['code']);
}
} Defensive patterns
Strategy: validation
Validate before calling
foreach ([CurrencySynth::class /* ... */] as $synthClass) {
foreach (['dehydrate', 'hydrate'] as $method) {
if (! method_exists($synthClass, $method)) {
throw new \LogicException("{$synthClass} lacks {$method}() and will throw on the round trip");
}
}
} Type guard
function synthCanHydrate(string $synthClass): bool
{
return method_exists($synthClass, 'hydrate');
} Try / catch
try {
Livewire::test(ComponentUsingCustomSynth::class)
->call('someAction'); // triggers hydration from the snapshot
} catch (\Exception $e) {
if (str_contains($e->getMessage(), 'must define a "hydrate" method')) {
// add the missing hydrate($value, $meta, $hydrateChild) to the custom synth
}
throw $e;
} Prevention
- Test the full round trip (render then call/update), not just the first render
- Implement dehydrate and hydrate in the same commit when writing a synth
- If a value only needs to be sent to the client, prefer a computed property over a synth
When it happens
Trigger: A registered custom synth defines $key, match() and dehydrate() but no hydrate(); the component renders fine, and the very next update request (any action or wire:model commit) throws when Livewire tries to reconstitute the property from the snapshot.
Common situations: Synths written and tested only against the initial render path; refactors that drop the method; copying a dehydrate-only example from docs or an AI suggestion.
Related errors
- You must define a "dehydrate" method
- You must define a "hydrateFromType" method
- Livewire: Class [{$meta['class']}] is not a valid Collection
- This synth doesn't support getting properties: ${get_class($
- This synth doesn't support setting properties: ${get_class($
AI-assisted analysis of livewire/livewire@1a3fde34c5 (2026-08-17).
Data as JSON: /api/errors/ab8eb4c660b0a335.
Report an issue: GitHub.