json_decode returns null: how to find out what is wrong with the JSON

When json_decode returns null, PHP knows why: ask it. The function json_last_error_msg() gives the reason in words, and it is nearly always one of five: a stray comma, single quotes, an invisible character at the start, text that is not UTF-8, or a reply that is not JSON at all (an error page, say).

First, ask PHP

<?php
$data = json_decode($text, true);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
  error_log('JSON: ' . json_last_error_msg());
  error_log('Start of text: ' . substr($text, 0, 200));
}

Logging the start of the text as well is what settles most cases: you see at once whether it begins with <html, a PHP warning or a strange character. On PHP 7.3 or later you can use the JSON_THROW_ON_ERROR option and catch the error with try/catch instead of testing by hand. Where to write that log is in writing your own log.

The causes, in order of frequency

The message says Cause Fix
Syntax error A trailing comma before } or ], single quotes instead of double, comments, or text that is not JSON. JSON accepts only double quotes and allows no trailing comma and no comments. Fix it at the source.
Syntax error, and the text starts with an odd space A BOM (byte order mark) at the start of the file, invisible in the editor. Strip it: $text = ltrim($text, "\xEF\xBB\xBF");. Better: save the file as “UTF-8 without BOM”.
Syntax error, and the text starts with <br /> or <b> A PHP warning was printed before the JSON. Fix the warning (see the PHP error log) and print nothing before the JSON.
Syntax error, and the text starts with <!DOCTYPE The reply is an HTML page, usually a 404 or 500 error. Check the request’s status code before decoding: calling an API with cURL.
Malformed UTF-8 characters The text is in ISO-8859-1 or another encoding. Convert it with mb_convert_encoding($text, 'UTF-8', 'ISO-8859-1') (the mbstring extension) or fix the source.
Maximum stack depth exceeded The JSON has more levels than allowed. Rare. Raise the third argument (the depth) or flatten the structure.

When the JSON is yours: the other side of the problem

If PHP is the one producing the JSON for a page or an app, the errors are the same seen in reverse. Always send the right header and print nothing before it:

<?php
header('Content-Type: application/json; charset=utf-8');
echo json_encode($reply, JSON_UNESCAPED_UNICODE);

A space or a blank line before the <?php, or after a closing ?>, spoils the reply. And if json_encode returns false, some text is not UTF-8: see the “Malformed UTF-8” row above.

Do not “clean” the JSON blindly with regular expressions. Removing characters until json_decode stops complaining hides the problem and can damage real data. Find the cause from the message and the start of the text, and fix it at the source.
Test the text outside your code. Pasting the JSON into an online validator shows the line and column of the error. Do not paste real data or keys into services you do not trust.

Have the json_last_error_msg message and the start of the text, and still cannot tell? Send us both, without keys or customer data.

Open a support ticket

SEE ALSO

Calling a web API from PHP with cURL

Writing your own log from PHP

A blank page in PHP: how to see the error

Where the PHP error log is

RECOMMENDED PRODUCT

Web hosting with cPanel

Domain and SSL included, daily backups and the panel you already know. from $6.60/mo (3-year plan, with coupon)

See plans
  • 0 Users Found This Useful
Was this answer helpful?