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

  1. 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().
  2. If the array comes from Grav's cache, clear it (bin/grav clear-cache) and let the blocks rebuild with current class names.
  3. After upgrades/refactors, verify the class still resolves: class_exists($type) && is_a($type, ContentBlockInterface::class, true).
  4. 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

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


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/ca2a1ddfd68f48c7. Report an issue: GitHub.