getgrav/grav · error · InvalidArgumentException
Bad data
Error message
Bad data
What it means
Thrown by ContentBlock::fromArray() when the serialized array cannot be identified as a content block: the '_type' key is missing or falsy, the 'id' key is missing or falsy, or '_type' does not name an existing class implementing ContentBlockInterface. fromArray() is the counterpart of toArray() (which emits '_type', '_version' and 'id'), so any other shape is rejected. The surrounding catch immediately re-wraps it as 'Cannot unserialize Block: Bad data' with the original exception chained.
Source
Thrown at system/src/Grav/Framework/ContentBlock/ContentBlock.php:70
*/
public static function create($id = null)
{
return new static($id);
}
/**
* @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)View on GitHub (pinned to 6040efed04)
Solutions
- Regenerate the source array from a live block: it must contain '_type' (class name), '_version' and 'id' — confirm with a fresh $block->toArray() before calling fromArray().
- If the array comes from Grav's cache, clear it (bin/grav clear-cache) and let the blocks rebuild with current class names.
- After upgrades/refactors, verify the class still resolves: class_exists($type) && is_a($type, ContentBlockInterface::class, true).
- Catch InvalidArgumentException around fromArray() and rebuild the block from its source content as a fallback.
Example fix
// before
$block = ContentBlock::fromArray($cached['block'] ?? []);
// after
$data = $cached['block'] ?? [];
$type = $data['_type'] ?? null;
if (!$type || !($data['id'] ?? null) || !is_a($type, ContentBlockInterface::class, true)) {
$block = ContentBlock::fromArray($freshBlock->toArray()); // rebuild from source
} else {
$block = ContentBlock::fromArray($data);
} Defensive patterns
Strategy: validation
Validate before calling
$type = $serialized['_type'] ?? null;
$id = $serialized['id'] ?? null;
if (!$type || !$id || !is_a($type, \Grav\Framework\ContentBlock\ContentBlockInterface::class, true)) {
// do not call fromArray(); rebuild the block from source content
} Type guard
function isSerializedContentBlock(array $data): bool
{
$type = $data['_type'] ?? null;
return (bool) $type && (bool) ($data['id'] ?? null)
&& is_a($type, \Grav\Framework\ContentBlock\ContentBlockInterface::class, true);
} Try / catch
try {
$block = ContentBlock::fromArray($data);
} catch (\InvalidArgumentException $e) {
$block = $source->buildBlock(); // regenerate; $e->getPrevious() holds the root cause
} Prevention
- Only pass arrays produced by toArray() into fromArray(); never hand-craft the shape.
- Version-stamp cache keys that persist block arrays and invalidate them on Grav upgrades.
- Add round-trip tests (toArray -> fromArray) for custom block classes in CI.
When it happens
Trigger: Calling ContentBlock::fromArray($array) with an array that was not produced by ContentBlock::toArray(): '_type' or 'id' key missing; '_type' naming a deleted, renamed or moved class (e.g. after refactoring a custom block class); '_type' naming a class that exists but no longer implements ContentBlockInterface; nested 'blocks' entries with the same problems.
Common situations: Replaying a cache written by an older Grav release after block classes moved; plugins hand-building block arrays instead of round-tripping toArray(); corrupted cache backends returning truncated-but-valid JSON; passing user-supplied arrays straight into fromArray().
Related errors
- Cannot unserialize Block: %s
- Unsupported version %s
- Creating directory failed for {filepath}
- Opening file for writing failed on error {$message}
- Failed to save file {filepath}
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/ca2a1ddfd68f48c7.
Report an issue: GitHub.