{"record":{"id":"8994ac37cd6022b4","repo":"getgrav/grav","slug":"encoding-json-failed-json-last-error-msg","errorCode":null,"errorMessage":"Encoding JSON failed: {json_last_error_msg}","messagePattern":"Encoding JSON failed: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/File/Formatter/JsonFormatter.php","lineNumber":150,"sourceCode":"     * Returns true if JSON objects will be converted into associative arrays.\n     *\n     * @return bool\n     */\n    public function getDecodeAssoc(): bool\n    {\n        return $this->getConfig('decode_assoc');\n    }\n\n    /**\n     * {@inheritdoc}\n     * @see FileFormatterInterface::encode()\n     */\n    public function encode($data): string\n    {\n        $encoded = @json_encode($data, $this->getEncodeOptions());\n\n        if ($encoded === false && json_last_error() !== JSON_ERROR_NONE) {\n            throw new RuntimeException('Encoding JSON failed: ' . json_last_error_msg());\n        }\n\n        return $encoded ?: '';\n    }\n\n    /**\n     * {@inheritdoc}\n     * @see FileFormatterInterface::decode()\n     */\n    public function decode($data)\n    {\n        $decoded = @json_decode($data, $this->getDecodeAssoc(), $this->getDecodeDepth(), $this->getDecodeOptions());\n\n        if (null === $decoded && json_last_error() !== JSON_ERROR_NONE) {\n            throw new RuntimeException('Decoding JSON failed: ' . json_last_error_msg());\n        }\n\n        return $decoded;","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/File/Formatter/JsonFormatter.php#L132-L168","documentation":"JsonFormatter::encode() calls @json_encode($data, $options) and throws when it returns false with json_last_error() set, appending json_last_error_msg(). Typical causes: malformed UTF-8 inside string data (JSON_ERROR_UTF8 / MALFORMED_UTF8), INF/NAN floats or resources that have no JSON representation, infinite recursion, and structures deeper than the configured depth (JSON_ERROR_DEPTH).","triggerScenarios":"Encoding arrays containing binary or legacy-encoded strings (ISO-8859-1/Windows-1252 from old DBs, filenames, uploads); payloads with NAN/INF; depth beyond the limit (512 default); accidentally captured closures/resources (e.g. when var-exporting an object graph).","commonSituations":"Migrating latin1 legacy data into Grav; form uploads exposing raw bytes; deep nested page data; data fetched from external APIs with broken encoding; serialized objects containing resources.","solutions":["Sanitize strings to UTF-8 before saving: a recursive walk applying mb_convert_encoding($s, 'UTF-8', 'UTF-8') drops invalid sequences.","Tolerate bad bytes at encode time: set JSON_INVALID_UTF8_SUBSTITUTE (or IGNORE) in the formatter's encode_options config.","Remove NAN/INF values and resources from the payload — json_encode cannot represent them.","Raise the encode depth in the JSON formatter config if the nesting is legitimate."],"exampleFix":"// before\n$file->save($data); // Encoding JSON failed: Malformed UTF-8 characters...\n\n// after\narray_walk_recursive($data, function (&$v) {\n    if (is_string($v)) { $v = mb_convert_encoding($v, 'UTF-8', 'UTF-8'); }\n});\n$file->save($data);","handlingStrategy":"validation","validationCode":"// Ensure every string is valid UTF-8 before encoding\narray_walk_recursive($data, function (&$v) {\n    if (is_string($v)) { $v = mb_convert_encoding($v, 'UTF-8', 'UTF-8'); }\n});","typeGuard":"function isUtf8Clean(mixed $value): bool\n{\n    if (is_string($value)) { return mb_check_encoding($value, 'UTF-8'); }\n    if (is_array($value)) { foreach ($value as $v) { if (!isUtf8Clean($v)) return false; } }\n    return true;\n}","tryCatchPattern":"try {\n    $file->save($data);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'Encoding JSON failed')) {\n        array_walk_recursive($data, fn(&$v) => is_string($v) && $v = mb_convert_encoding($v, 'UTF-8', 'UTF-8'));\n        $file->save($data); // single sanitized retry\n    }\n}","preventionTips":["Normalize all input to UTF-8 at system boundaries (forms, APIs, uploads).","Use utf8mb4 for MySQL connections so retrieved strings are clean.","Configure encode options (depth, invalid-UTF8 handling) to match your data."],"tags":["php","grav","json","encoding","utf-8","serialization"],"backgroundTag":"json-encode-error","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}