{"record":{"id":"ccdd219d1efc1a9c","repo":"getgrav/grav","slug":"encoding-markdown-failed","errorCode":null,"errorMessage":"Encoding markdown failed","messagePattern":"Encoding markdown failed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/Formatter/MarkdownFormatter.php","lineNumber":103,"sourceCode":"    public function encode($data): string\n    {\n        $headerVar = $this->getHeaderField();\n        $bodyVar = $this->getBodyField();\n\n        $header = isset($data[$headerVar]) ? (array) $data[$headerVar] : [];\n        $body = isset($data[$bodyVar]) ? (string) $data[$bodyVar] : '';\n\n        // Create Markdown file with YAML header.\n        $encoded = '';\n        if ($header) {\n            $encoded = \"---\\n\" . trim($this->getHeaderFormatter()->encode($data['header'])) . \"\\n---\\n\\n\";\n        }\n        $encoded .= $body;\n\n        // Normalize line endings to Unix style.\n        $encoded = preg_replace(\"/(\\r\\n|\\r)/u\", \"\\n\", $encoded);\n        if (null === $encoded) {\n            throw new RuntimeException('Encoding markdown failed');\n        }\n\n        return $encoded;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @see FileFormatterInterface::decode()\n     */\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 => [],","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/Formatter/MarkdownFormatter.php#L85-L121","documentation":"MarkdownFormatter::encode() assembles the YAML frontmatter and body, then normalizes line endings with preg_replace(\"/(\\r\\n|\\r)/u\", \"\\n\", $encoded). The /u modifier makes PCRE validate the subject as UTF-8; invalid bytes force preg_replace to return null, which this null-check converts into a RuntimeException. Cause: the header array's encoded form or the body string is not valid UTF-8.","triggerScenarios":"Encoding a markdown file whose frontmatter values or body contain non-UTF-8 bytes: text pasted from Windows-1252/latin1 sources, strings from non-utf8mb4 DB columns, double-encoded or binary-contaminated content flowing into $data['header'] or the body field.","commonSituations":"Content pasted from word processors in legacy encodings; legacy site imports; DB connections without utf8mb4; metadata (titles, summaries) captured from external feeds with broken encoding.","solutions":["Convert the source encoding before saving: mb_convert_encoding($body, 'UTF-8', 'Windows-1252') (identify the real source encoding first).","Drop invalid sequences lossily: mb_convert_encoding($s, 'UTF-8', 'UTF-8') or iconv('UTF-8', 'UTF-8//IGNORE', $s).","Guard inputs with mb_check_encoding($string, 'UTF-8') and reject or sanitize earlier in the pipeline.","Fix the storage layer (utf8mb4 connection charset) so strings arrive clean."],"exampleFix":"// before\n$file->save(['header' => $header, 'markdown' => $body]);\n\n// after\n$body = mb_convert_encoding((string) $body, 'UTF-8', 'UTF-8');\narray_walk_recursive($header, function (&$v) {\n    if (is_string($v)) { $v = mb_convert_encoding($v, 'UTF-8', 'UTF-8'); }\n});\n$file->save(['header' => $header, 'markdown' => $body]);","handlingStrategy":"validation","validationCode":"// Validate both parts before encode()\n$bodyOk = mb_check_encoding((string) ($data['markdown'] ?? ''), 'UTF-8');\n$headerOk = true;\narray_walk_recursive($data['header'] ?? [], function ($v) use (&$headerOk) {\n    if (is_string($v)) { $headerOk = $headerOk && mb_check_encoding($v, 'UTF-8'); }\n});\nif (!$bodyOk || !$headerOk) {\n    // convert/drop invalid bytes before calling the formatter\n}","typeGuard":"function isUtf8String(mixed $value): bool\n{\n    return is_string($value) && mb_check_encoding($value, 'UTF-8');\n}","tryCatchPattern":"try {\n    $file->save($data);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'Encoding markdown failed')) {\n        $data['markdown'] = mb_convert_encoding($data['markdown'], 'UTF-8', 'UTF-8');\n        $file->save($data); // retry once after sanitizing\n    }\n}","preventionTips":["Enforce UTF-8 at every input boundary (forms, imports, feeds).","Keep DB connections on utf8mb4 so frontmatter values are clean.","Reject or sanitize binary uploads before they reach page data."],"tags":["php","grav","markdown","utf-8","preg-replace","frontmatter"],"backgroundTag":"invalid-utf8","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}