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

  1. 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.
  2. Batch-fix remaining pages the same way (verify each file's source encoding first).
  3. Strip invalid bytes when lossy conversion is acceptable: iconv -c -f UTF-8 -t UTF-8 page.md.
  4. 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

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


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/76834af16f3fb819. Report an issue: GitHub.