getgrav/grav · error · InvalidArgumentException

Cannot unserialize '{$type}': Bad data

Error message

Cannot unserialize '{$type}': Bad data

What it means

FlexObject::doUnserialize() (line 1016) rebuilds an object from a serialized array and requires the keys 'key', 'type' and 'elements' to be present; otherwise it throws InvalidArgumentException naming the payload's 'type' field (or 'unknown'). It guards against hand-built, truncated, or version-mismatched serialized flex payloads reaching the object layer.

Source

Thrown at system/src/Grav/Framework/Flex/FlexObject.php:1016

        return [
            'type' => $this->getFlexType(),
            'key' => $this->getKey(),
            'elements' => $this->getElements(),
            'storage' => $this->getMetaData()
        ];
    }

    /**
     * @param array $serialized
     * @param FlexDirectory|null $directory
     * @return void
     */
    protected function doUnserialize(array $serialized, ?FlexDirectory $directory = null): void
    {
        $type = $serialized['type'] ?? 'unknown';

        if (!isset($serialized['key'], $serialized['type'], $serialized['elements'])) {
            throw new \InvalidArgumentException("Cannot unserialize '{$type}': Bad data");
        }

        if (null === $directory) {
            $directory = $this->getFlexContainer()->getDirectory($type);
            if (!$directory) {
                throw new \InvalidArgumentException("Cannot unserialize Flex type '{$type}': Directory not found");
            }
        }

        $this->setFlexDirectory($directory);
        $this->setMetaData($serialized['storage']);
        $this->setKey($serialized['key']);
        $this->setElements($serialized['elements']);
    }

    /**
     * @return array
     */

View on GitHub (pinned to 6040efed04)

Solutions

  1. Clear the affected cache/session storage (bin/grav cache, session store) so payloads are regenerated in the current format.
  2. Only unserialize arrays produced by FlexObject::serialize() of the same class and Grav version.
  3. If stored payloads must be migrated, normalize them first: ensure key, type and elements exist (fill defaults) before unserializing.

Example fix

// before
$obj = MyObject::fromUnserialized($cachedArray); // missing 'elements' -> throws

// after
if (!isset($cachedArray['key'], $cachedArray['type'], $cachedArray['elements'])) {
    $obj = $directory->getObject($key); // discard stale payload, reload from storage
} else {
    $obj = MyObject::fromUnserialized($cachedArray);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!isset($cached['key'], $cached['type'], $cached['elements'])) {
    // stale/corrupt payload: drop it and reload from storage
    $object = $directory->getObject($key);
} else {
    $object = $objectClass::fromUnserialized($cached);
}

Type guard

function isWellFormedFlexPayload(array $payload): bool
{
    return isset($payload['key'], $payload['type'], $payload['elements']);
}

Try / catch

try {
    $object = $objectClass::fromUnserialized($cached);
} catch (\InvalidArgumentException $e) {
    // invalidate the cache entry and rebuild from the directory/storage
    $cache->delete($cacheKey);
    $object = $directory->getObject($key);
}

Prevention

When it happens

Trigger: Unserializing an array not produced by the matching FlexObject::serialize() (hand-crafted, partial copy, or re-keyed); cache/session entries written by an older Grav or a different object class for the same type; payloads truncated by a store with length limits.

Common situations: After upgrading Grav or a plugin whose flex serialization shape changed while stale cache/session data persists; Redis/session stores retaining pre-upgrade objects; custom caching code storing only part of serialize() output.

Related errors


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