{"record":{"id":"078fb3b21bca8ec1","repo":"getgrav/grav","slug":"decoding-serialized-data-failed","errorCode":null,"errorMessage":"Decoding serialized data failed","messagePattern":"Decoding serialized data failed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/Formatter/SerializeFormatter.php","lineNumber":71,"sourceCode":"     * {@inheritdoc}\n     * @see FileFormatterInterface::encode()\n     */\n    public function encode($data): string\n    {\n        return serialize($this->preserveLines($data, [\"\\n\", \"\\r\"], ['\\\\n', '\\\\r']));\n    }\n\n    /**\n     * {@inheritdoc}\n     * @see FileFormatterInterface::decode()\n     */\n    public function decode($data)\n    {\n        $classes = $this->getOptions()['allowed_classes'] ?? false;\n        $decoded = @unserialize($data, ['allowed_classes' => $classes]);\n\n        if ($decoded === false && $data !== serialize(false)) {\n            throw new RuntimeException('Decoding serialized data failed');\n        }\n\n        return $this->preserveLines($decoded, ['\\\\n', '\\\\r'], [\"\\n\", \"\\r\"]);\n    }\n\n    /**\n     * Preserve new lines, recursive function.\n     *\n     * @param array $search\n     * @param array $replace\n     * @return mixed\n     */\n    protected function preserveLines(mixed $data, array $search, array $replace)\n    {\n        if (is_string($data)) {\n            $data = str_replace($search, $replace, $data);\n        } elseif (is_array($data)) {\n            foreach ($data as &$value) {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/Formatter/SerializeFormatter.php#L53-L89","documentation":"Grav's SerializeFormatter::decode() calls PHP's unserialize() (with notices suppressed) and throws this RuntimeException when unserialize() returns false for input that is not literally serialize(false). It means the byte stream handed to the formatter is not valid, complete PHP-serialized data. Typical root causes are truncated or hand-edited files, line-ending/encoding mangling during transfer, or data produced by a different serializer.","triggerScenarios":"Reading a saved .serialized cache/state file that was corrupted, emptied, or truncated; calling $formatter->decode() on a string that was never produced by serialize() (e.g. JSON or plain text); transferring serialized files in a way that converts \\n/\\r or strips bytes; a file written by an incompatible PHP serialization format.","commonSituations":"Deploying or copying the grav data/cache directories between servers with FTP in ASCII mode; a cache cleaner or editor truncating files under user/data; switching a file's formatter configuration from JsonFormatter to SerializeFormatter while old files still contain the previous format.","solutions":["Delete or restore the offending serialized file so Grav regenerates it from defaults (check user/data, user/cache, backup directories).","Verify the file was not modified: compare length/checksum against a backup; re-export rather than hand-edit serialized data.","If the file legitimately contains another format, configure the correct formatter (JsonFormatter/YamlFormatter) for that file instead of SerializeFormatter.","Wrap decode() in a try-catch that treats unreadable data as 'file missing' and rebuilds it."],"exampleFix":"// before\n$data = $file->load(); // RuntimeException: Decoding serialized data failed\n\n// after\ntry {\n    $data = $file->load();\n} catch (RuntimeException $e) {\n    @unlink($file->filename()); // discard corrupt state, rebuild\n    $data = $defaults;\n    $file->save($data);\n}","handlingStrategy":"try-catch","validationCode":"// Cheap pre-check: valid serialized streams start with a type token\nif (!is_string($data) || $data === '' || !preg_match('/^[a-zOCdbsiNa]:\\d+/i', $data)) {\n    // not serialized data; skip decode or rebuild defaults\n}","typeGuard":null,"tryCatchPattern":"try {\n    $decoded = $formatter->decode($data);\n} catch (\\Grav\\Framework\\File\\Formatter\\Exception\\RuntimeException $e) {\n    // treat as corrupt: log, restore defaults, and continue\n    $decoded = $defaults;\n    $log->warning('Corrupt serialized file {file}: {msg}', ['file' => $filename, 'msg' => $e->getMessage()]);\n}","preventionTips":["Never hand-edit serialized files; regenerate them programmatically.","Keep serialized state files out of editors/FTP ASCII transfers; deploy archives instead.","Prefer JsonFormatter or YamlFormatter for user-visible data — they fail with clearer errors.","Back up the data directory so corrupt state can be restored."],"tags":["php","serialization","unserialize","grav","file-corruption"],"backgroundTag":"unserialize-failed","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}