{"record":{"id":"ea09e6f6ef6fe9fa","repo":"getgrav/grav","slug":"cannot-unserialize-flex-type-type-directory","errorCode":null,"errorMessage":"Cannot unserialize Flex type '{$type}': Directory not found","messagePattern":"Cannot unserialize Flex type '(.+?)': Directory not found","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Flex/FlexObject.php","lineNumber":1022,"sourceCode":"    }\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     */\n    protected function getTemplateConfig()\n    {\n        $config = $this->getFlexDirectory()->getConfig('site.templates', []);\n        $defaults = array_replace($config['defaults'] ?? [], $config['object']['defaults'] ?? []);\n        $config['object']['defaults'] = $defaults;\n","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Flex/FlexObject.php#L1004-L1040","documentation":"FlexObject::doUnserialize() rebuilds an object from serialized data. When no FlexDirectory is passed in, it asks the Flex container (Grav::instance()['flex']) for the directory registered under the serialized 'type'. If no directory is registered for that type, the object cannot be rehydrated and an InvalidArgumentException is thrown. This almost always means the Flex type existed when the object was cached/serialized, but is no longer registered at unserialize time.","triggerScenarios":"Calling unserialize() (or $flexObject->__unserialize()/unserialize(string) on a Flex object) whose serialized 'type' has no matching directory in the Flex container; fetching an object from cache after the blueprint or plugin providing that Flex type was removed, renamed, or disabled; unserializing a Flex object before the plugin that registers its directory has booted.","commonSituations":"A plugin (e.g. flex-objects with a custom directory) is deactivated or its blueprint type is renamed while cached data still references the old type; upgrading Grav or a plugin changes/deprecates a Flex type; running code in a context (CLI, tests) where the Flex container was never initialized with that directory.","solutions":["Check that the Flex type is still registered: dump Grav::instance()['flex']->getDirectories() and confirm the type key from the serialized data exists.","If a plugin provided the directory, re-enable it or update the blueprint/collection definition so the directory is registered under the same type name.","Clear stale cache (cache/ folder, or bin/grav clearcache) so old serialized Flex objects referencing the removed type are purged.","If the type was intentionally renamed, migrate the serialized data (update its 'type' entry) or pass an explicit FlexDirectory to doUnserialize via the object's unserialize path instead of relying on container lookup.","In CLI/test contexts, boot Grav (e.g. Grav::instance()['accounts'] trigger or load the flex-objects plugin) before unserializing Flex objects."],"exampleFix":"// before\n$object = unserialize($cachedString); // Flex type 'old-type' no longer registered -> throws\n\n// after\n$flex = Grav::instance()['flex'];\n$type = $serialized['type'] ?? null;\n$directory = $type ? $flex->getDirectory($type) : null;\nif (null === $directory) {\n    // regenerate instead of unserializing stale data\n    $object = $flex->getDirectory('new-type')->getObject($key);\n} else {\n    $object = unserialize($cachedString);\n}","handlingStrategy":"validation","validationCode":"$flex = \\Grav\\Common\\Grav::instance()['flex'] ?? null;\n$type = $serialized['type'] ?? null;\n$directory = ($flex && $type) ? $flex->getDirectory($type) : null;\nif (null === $directory) {\n    // skip unserialize; regenerate the object or log & drop stale cache\n    return $flex ? $flex->getDirectory('fallback-type')->getObject($key) : null;\n}\n$object = unserialize($cachedString);","typeGuard":"/** @param array{type?: string} $serialized */\nfunction flexTypeIsRegistered(array $serialized): bool\n{\n    $flex = \\Grav\\Common\\Grav::instance()['flex'] ?? null;\n    $type = $serialized['type'] ?? null;\n\n    return $flex instanceof \\Grav\\Framework\\Flex\\Interfaces\\FlexContainerInterface\n        && \\is_string($type)\n        && $flex->getDirectory($type) instanceof \\Grav\\Framework\\Flex\\FlexDirectory;\n}","tryCatchPattern":"try {\n    $object = unserialize($cached);\n} catch (\\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'Directory not found')) {\n        // stale cache entry for a removed Flex type: invalidate and regenerate\n        $cache->delete($key);\n        $object = $flex->getDirectory($type)->getObject($objectKey);\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Register all Flex directories (plugins enabled) before any code that unserializes Flex objects, including CLI and cron contexts.","When renaming or removing a Flex type, ship a migration that clears caches containing serialized objects of the old type.","Version-prefix cache keys with the Flex type name so invalidation on type changes is automatic."],"tags":["flex","unserialize","grav","directory-not-found","cache"],"backgroundTag":"flex-directory-not-found","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}