{"record":{"id":"6ada7a7110b310d4","repo":"getgrav/grav","slug":"cannot-unserialize-type-bad-data","errorCode":null,"errorMessage":"Cannot unserialize '{$type}': Bad data","messagePattern":"Cannot unserialize '(.+?)': Bad data","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Flex/FlexObject.php","lineNumber":1016,"sourceCode":"        return [\n            'type' => $this->getFlexType(),\n            'key' => $this->getKey(),\n            'elements' => $this->getElements(),\n            'storage' => $this->getMetaData()\n        ];\n    }\n\n    /**\n     * @param array $serialized\n     * @param FlexDirectory|null $directory\n     * @return void\n     */\n    protected function doUnserialize(array $serialized, ?FlexDirectory $directory = null): void\n    {\n        $type = $serialized['type'] ?? 'unknown';\n\n        if (!isset($serialized['key'], $serialized['type'], $serialized['elements'])) {\n            throw new \\InvalidArgumentException(\"Cannot unserialize '{$type}': Bad data\");\n        }\n\n        if (null === $directory) {\n            $directory = $this->getFlexContainer()->getDirectory($type);\n            if (!$directory) {\n                throw new \\InvalidArgumentException(\"Cannot unserialize Flex type '{$type}': Directory not found\");\n            }\n        }\n\n        $this->setFlexDirectory($directory);\n        $this->setMetaData($serialized['storage']);\n        $this->setKey($serialized['key']);\n        $this->setElements($serialized['elements']);\n    }\n\n    /**\n     * @return array\n     */","sourceCodeStart":998,"sourceCodeEnd":1034,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Flex/FlexObject.php#L998-L1034","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clear the affected cache/session storage (bin/grav cache, session store) so payloads are regenerated in the current format.","Only unserialize arrays produced by FlexObject::serialize() of the same class and Grav version.","If stored payloads must be migrated, normalize them first: ensure key, type and elements exist (fill defaults) before unserializing."],"exampleFix":"// before\n$obj = MyObject::fromUnserialized($cachedArray); // missing 'elements' -> throws\n\n// after\nif (!isset($cachedArray['key'], $cachedArray['type'], $cachedArray['elements'])) {\n    $obj = $directory->getObject($key); // discard stale payload, reload from storage\n} else {\n    $obj = MyObject::fromUnserialized($cachedArray);\n}","handlingStrategy":"validation","validationCode":"if (!isset($cached['key'], $cached['type'], $cached['elements'])) {\n    // stale/corrupt payload: drop it and reload from storage\n    $object = $directory->getObject($key);\n} else {\n    $object = $objectClass::fromUnserialized($cached);\n}","typeGuard":"function isWellFormedFlexPayload(array $payload): bool\n{\n    return isset($payload['key'], $payload['type'], $payload['elements']);\n}","tryCatchPattern":"try {\n    $object = $objectClass::fromUnserialized($cached);\n} catch (\\InvalidArgumentException $e) {\n    // invalidate the cache entry and rebuild from the directory/storage\n    $cache->delete($cacheKey);\n    $object = $directory->getObject($key);\n}","preventionTips":["Store only complete serialize() output; never hand-assemble payload fragments.","Version your cache keys by Grav/plugin version so upgrades invalidate old payloads.","Treat unserialize failures as cache misses: delete and reload rather than crash."],"tags":["flex","serialization","cache","session","data-integrity"],"backgroundTag":"corrupted-serialized-data","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}