getgrav/grav · error · RuntimeException
Decoding JSON failed: {json_last_error_msg}
Error message
Decoding JSON failed: {json_last_error_msg} What it means
JsonFormatter::decode() calls @json_decode($data, $assoc, $depth, $options) and throws when the result is null and json_last_error() reports an error: syntax errors (truncation, trailing commas, single quotes, comments), malformed UTF-8, or nesting deeper than the configured decode depth. A file whose entire content is literal null decodes to null without an error and returns normally — the json_last_error() check distinguishes that case.
Source
Thrown at system/src/Grav/Framework/File/Formatter/JsonFormatter.php:165
$encoded = @json_encode($data, $this->getEncodeOptions());
if ($encoded === false && json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Encoding JSON failed: ' . json_last_error_msg());
}
return $encoded ?: '';
}
/**
* {@inheritdoc}
* @see FileFormatterInterface::decode()
*/
public function decode($data)
{
$decoded = @json_decode($data, $this->getDecodeAssoc(), $this->getDecodeDepth(), $this->getDecodeOptions());
if (null === $decoded && json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Decoding JSON failed: ' . json_last_error_msg());
}
return $decoded;
}
}
View on GitHub (pinned to 6040efed04)
Solutions
- Locate the error: php -r 'json_decode(file_get_contents("f.json")); echo json_last_error_msg();' or jq . f.json, then fix the reported construct.
- Strip a leading BOM: $data = preg_replace('/^\xEF\xBB\xBF/', '', $data).
- Remove JSON-invalid syntax: comments, trailing commas, single-quoted strings.
- If the nesting is legitimate, increase decode_depth in the JSON formatter/file configuration.
Example fix
# before: RuntimeException "Decoding JSON failed: Syntax error" jq . user/data/broken.json # pinpoints the parse error # fix the reported line (e.g. remove trailing comma), then: # $dataFile->load() succeeds
Defensive patterns
Strategy: validation
Validate before calling
// PHP 8.3+: cheap syntax gate
if (function_exists('json_validate') && !json_validate($raw)) {
// fix the payload before JsonFormatter::decode()
}
// older PHP: trial decode
json_decode($raw);
if (json_last_error() !== JSON_ERROR_NONE) { /* handle */ } Try / catch
try {
$data = $jsonFormatter->decode($raw);
} catch (\RuntimeException $e) {
// json_last_error_msg() is embedded; fall back to defaults and flag the file
$data = $defaults;
$log->error($e->getMessage());
} Prevention
- Lint every JSON file in CI (jq, json_decode checks).
- Strip BOMs when ingesting external JSON.
- Edit data files through the formatter's save() rather than by hand.
When it happens
Trigger: Loading a .json file with a syntax error; truncated files from an interrupted write; a UTF-8 BOM at the start (json_decode rejects it); nesting beyond decode depth; JSON with // comments or trailing commas from hand editing.
Common situations: Hand-edited site/plugin configuration; editors saving with BOM; partially uploaded files; JSON built by string concatenation; deep structures hitting the default 512 depth.
Related errors
- Decoding INI failed
- Failed to load file '%s': %s
- CSV header missing
- Badly formatted CSV line: {line}
- Encoding JSON failed: {json_last_error_msg}
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/da25a94abf466bda.
Report an issue: GitHub.