getgrav/grav · error · RuntimeException
Decoding markdown failed
Error message
Decoding markdown failed
What it means
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.
Source
Thrown at system/src/Grav/Framework/File/Formatter/MarkdownFormatter.php:130
*/
public function decode($data): array
{
$headerVar = $this->getHeaderField();
$bodyVar = $this->getBodyField();
$rawVar = $this->getRawField();
// Define empty content
$content = [
$headerVar => [],
$bodyVar => ''
];
$headerRegex = "/^---\n(.+?)\n---\n{0,}(.*)$/uis";
// Normalize line endings to Unix style.
$data = preg_replace("/(\r\n|\r)/u", "\n", $data);
if (null === $data) {
throw new RuntimeException('Decoding markdown failed');
}
// Parse header.
preg_match($headerRegex, ltrim($data), $matches);
if (empty($matches)) {
$content[$bodyVar] = $data;
} else {
// Normalize frontmatter.
$frontmatter = preg_replace("/\n\t/", "\n ", $matches[1]);
if ($rawVar) {
$content[$rawVar] = $frontmatter;
}
$content[$headerVar] = $this->getHeaderFormatter()->decode($frontmatter);
$content[$bodyVar] = $matches[2];
}
return $content;
}View on GitHub (pinned to 6040efed04)
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.
Example fix
# before: RuntimeException "Decoding markdown failed" file -i user/pages/01.about/page.md # charset=iso-8859-1 iconv -f ISO-8859-1 -t UTF-8 user/pages/01.about/page.md -o /tmp/fixed.md mv /tmp/fixed.md user/pages/01.about/page.md # after: decode() succeeds
Defensive patterns
Strategy: validation
Validate before calling
$raw = is_file($path) && is_readable($path) ? file_get_contents($path) : null;
if (is_string($raw) && !mb_check_encoding($raw, 'UTF-8')) {
// decode() will abort: convert the file first
$raw = mb_convert_encoding($raw, 'UTF-8', 'UTF-8');
} Type guard
function isUtf8File(string $path): bool
{
$raw = @file_get_contents($path);
return is_string($raw) && mb_check_encoding($raw, 'UTF-8');
} Try / catch
try {
$page = $markdownFormatter->decode($raw);
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'Decoding markdown failed') && !mb_check_encoding($raw, 'UTF-8')) {
$page = $markdownFormatter->decode(mb_convert_encoding($raw, 'UTF-8', 'UTF-8'));
} else {
throw $e;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Old sites imported into Grav; pages edited with locale-specific encodings; content copied from PDFs or word processors; files transferred through encoding-mangling pipelines.
Related errors
- Encoding JSON failed: {json_last_error_msg}
- Encoding markdown failed
- json_encode(): failed to encode dependencies
- Bad data
- Cannot unserialize Block: %s
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/76834af16f3fb819.
Report an issue: GitHub.