{"record":{"id":"76834af16f3fb819","repo":"getgrav/grav","slug":"decoding-markdown-failed","errorCode":null,"errorMessage":"Decoding markdown failed","messagePattern":"Decoding markdown failed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/Formatter/MarkdownFormatter.php","lineNumber":130,"sourceCode":"     */\n    public function decode($data): array\n    {\n        $headerVar = $this->getHeaderField();\n        $bodyVar = $this->getBodyField();\n        $rawVar = $this->getRawField();\n\n        // Define empty content\n        $content = [\n            $headerVar => [],\n            $bodyVar => ''\n        ];\n\n        $headerRegex = \"/^---\\n(.+?)\\n---\\n{0,}(.*)$/uis\";\n\n        // Normalize line endings to Unix style.\n        $data = preg_replace(\"/(\\r\\n|\\r)/u\", \"\\n\", $data);\n        if (null === $data) {\n            throw new RuntimeException('Decoding markdown failed');\n        }\n\n        // Parse header.\n        preg_match($headerRegex, ltrim($data), $matches);\n        if (empty($matches)) {\n            $content[$bodyVar] = $data;\n        } else {\n            // Normalize frontmatter.\n            $frontmatter = preg_replace(\"/\\n\\t/\", \"\\n    \", $matches[1]);\n            if ($rawVar) {\n                $content[$rawVar] = $frontmatter;\n            }\n            $content[$headerVar] = $this->getHeaderFormatter()->decode($frontmatter);\n            $content[$bodyVar] = $matches[2];\n        }\n\n        return $content;\n    }","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/Formatter/MarkdownFormatter.php#L112-L148","documentation":"MarkdownFormatter::decode() applies the same /u UTF-8-validating preg_replace line-ending normalization to the raw file contents before splitting frontmatter from body; when the bytes are not valid UTF-8, preg_replace returns null and decoding aborts with this RuntimeException. Encoding is validated before any structure is parsed — even a perfectly shaped page fails if its bytes are mis-encoded.","triggerScenarios":"Loading a .md file containing non-UTF-8 bytes: legacy pages saved in latin1/Windows-1252, binary noise from bad transfers, mixed encodings after a server migration or FTP in the wrong mode.","commonSituations":"Old sites imported into Grav; pages edited with locale-specific encodings; content copied from PDFs or word processors; files transferred through encoding-mangling pipelines.","solutions":["Identify and convert the file: file -i page.md, then iconv -f ISO-8859-1 -t UTF-8 page.md -o fixed.md && mv fixed.md page.md.","Batch-fix remaining pages the same way (verify each file's source encoding first).","Strip invalid bytes when lossy conversion is acceptable: iconv -c -f UTF-8 -t UTF-8 page.md.","Configure editors, transfers and pipelines to write UTF-8 without BOM going forward."],"exampleFix":"# before: RuntimeException \"Decoding markdown failed\"\nfile -i user/pages/01.about/page.md     # charset=iso-8859-1\niconv -f ISO-8859-1 -t UTF-8 user/pages/01.about/page.md -o /tmp/fixed.md\nmv /tmp/fixed.md user/pages/01.about/page.md\n# after: decode() succeeds","handlingStrategy":"validation","validationCode":"$raw = is_file($path) && is_readable($path) ? file_get_contents($path) : null;\nif (is_string($raw) && !mb_check_encoding($raw, 'UTF-8')) {\n    // decode() will abort: convert the file first\n    $raw = mb_convert_encoding($raw, 'UTF-8', 'UTF-8');\n}","typeGuard":"function isUtf8File(string $path): bool\n{\n    $raw = @file_get_contents($path);\n    return is_string($raw) && mb_check_encoding($raw, 'UTF-8');\n}","tryCatchPattern":"try {\n    $page = $markdownFormatter->decode($raw);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'Decoding markdown failed') && !mb_check_encoding($raw, 'UTF-8')) {\n        $page = $markdownFormatter->decode(mb_convert_encoding($raw, 'UTF-8', 'UTF-8'));\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Store all page/content files as UTF-8 without BOM; set editor defaults accordingly.","Run encoding checks (file -i) during site imports and migrations.","Quarantine mis-encoded uploads instead of feeding them to the formatter."],"tags":["php","grav","markdown","utf-8","encoding","page-content"],"backgroundTag":"invalid-utf8","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}