getgrav/grav · error · InvalidArgumentException
Cannot unserialize Block: %s
Error message
Cannot unserialize Block: %s
What it means
Umbrella exception from ContentBlock::fromArray(): any Exception raised while reconstructing the block — the 'Bad data' guard, a failure inside `new $type($id)`, or anything thrown by $instance->build($serialized) (build() runs checkVersion() and recurses into self::fromArray() for every nested block) — is caught and re-thrown as this InvalidArgumentException with the original message interpolated via sprintf and the original exception chained as previous. Read $e->getPrevious() for the root cause.
Source
Thrown at system/src/Grav/Framework/ContentBlock/ContentBlock.php:77
* @param array $serialized
* @return ContentBlockInterface
* @throws InvalidArgumentException
*/
public static function fromArray(array $serialized)
{
try {
$type = $serialized['_type'] ?? null;
$id = $serialized['id'] ?? null;
if (!$type || !$id || !is_a($type, ContentBlockInterface::class, true)) {
throw new InvalidArgumentException('Bad data');
}
/** @var ContentBlockInterface $instance */
$instance = new $type($id);
$instance->build($serialized);
} catch (Exception $e) {
throw new InvalidArgumentException(sprintf('Cannot unserialize Block: %s', $e->getMessage()), $e->getCode(), $e);
}
return $instance;
}
/**
* Block constructor.
*
* @param string|null $id
*/
public function __construct($id = null)
{
$this->id = $id ? (string) $id : $this->generateId();
}
/**
* @return string
*/View on GitHub (pinned to 6040efed04)
Solutions
- Inspect $e->getPrevious() — it carries the real cause ('Bad data', 'Unsupported version N', or a constructor/build error).
- Clear the cache (bin/grav clear-cache) so blocks regenerate under the current version and class names.
- Fix the referenced block class so that `new $type($id)` and build() cannot throw on well-formed data.
- Catch this exception at the call site and regenerate the block from source content instead of surfacing the failure.
Example fix
// before
$block = ContentBlock::fromArray($cached);
// after
try {
$block = ContentBlock::fromArray($cached);
} catch (\InvalidArgumentException $e) {
$log->warning('Block unserialize failed: ' . $e->getMessage(), ['previous' => $e->getPrevious()]);
$block = $page->buildContentBlock(); // regenerate from source
} Defensive patterns
Strategy: try-catch
Try / catch
try {
$block = ContentBlock::fromArray($cached);
} catch (\InvalidArgumentException $e) {
// umbrella failure: inspect $e->getPrevious(), then regenerate
$log->warning($e->getMessage(), ['root' => $e->getPrevious()]);
$block = $page->buildContentBlock();
} Prevention
- Treat unserialization as fallible: always pair fromArray() with a rebuild path.
- Log the chained previous exception — the wrapper message alone hides the cause.
- Clear caches on deploy so stale serialized blocks never reach production code.
When it happens
Trigger: fromArray() on partially corrupted arrays; a '_version' mismatch bubbling up from build() as 'Unsupported version N'; a custom block class whose constructor or build() throws; deeply nested block trees where an inner block fails validation.
Common situations: Upgrading Grav with stale cached pages; cache/session backends returning truncated data; custom block implementations that throw during build(); data serialized by one Grav version replayed by another (dev cache imported into prod, rollback after upgrade).
Related errors
- Bad data
- Unsupported version %s
- Failed to load file '%s': %s
- Creating directory failed for {filepath}
- Opening file for writing failed on error {$message}
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/de58e64fb9b4295d.
Report an issue: GitHub.