Skip to content
jsonbeautifiers
English
PHP Constant names and messages from the PHP manual.

json_decode() returns NULL

PHP does not throw on invalid JSON by default. json_decode simply returns NULL, which is also a legitimate result for the input "null", so you cannot tell failure from success by the return value alone. The first job is to make PHP tell you what went wrong.

Paste your JSON and see exactly where it breaks

Input

Nothing you paste leaves your browser. The connect-src allowlist makes that a browser guarantee rather than a promise. Check it yourself

What actually causes it

Ranked by how often each one turns out to be the answer.

  1. 01 You have no error message yet

    Call json_last_error_msg() immediately after decoding, or pass the JSON_THROW_ON_ERROR flag so a JsonException is raised instead. Without one of these you are debugging blind, which is why this problem takes people so long.

    Breaks

    $data = json_decode($body, true);
    if ($data === null) { /* why? */ }

    Works

    $data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
    // or
    $data = json_decode($body, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new RuntimeException(json_last_error_msg());
    }
  2. 02 A UTF-8 byte order mark at the start of the file

    A classic in PHP because file_get_contents returns the BOM and json_decode rejects it. Strip the first three bytes if they are EF BB BF.

  3. 03 Malformed UTF-8, giving JSON_ERROR_UTF8

    "Malformed UTF-8 characters, possibly incorrectly encoded" usually means data came out of a Latin-1 database column. Convert with mb_convert_encoding before decoding.

  4. 04 A warning or notice printed before the JSON

    Any output before your response body ends up in it. Turn display_errors off in production and log instead.

  5. 05 Nesting deeper than the default limit, giving JSON_ERROR_DEPTH

    json_decode defaults to a depth of 512. Raise the third argument if the data is genuinely that deep.

Questions

What are the JSON_ERROR constants?
JSON_ERROR_NONE (0), JSON_ERROR_DEPTH (1, maximum stack depth exceeded), JSON_ERROR_STATE_MISMATCH (2), JSON_ERROR_CTRL_CHAR (3, unexpected control character found), JSON_ERROR_SYNTAX (4, syntax error, malformed JSON), JSON_ERROR_UTF8 (5, malformed UTF-8 characters), plus JSON_ERROR_RECURSION, JSON_ERROR_INF_OR_NAN, JSON_ERROR_UNSUPPORTED_TYPE, JSON_ERROR_INVALID_PROPERTY_NAME, JSON_ERROR_UTF16 and JSON_ERROR_NON_BACKED_ENUM.
How do I tell a NULL result from a NULL failure?
json_last_error() === JSON_ERROR_NONE means the decode succeeded, so a NULL return is the genuine value null. Any other code means it failed.

Fix it now

Paste the payload into the tool above, or go straight to the one built for this job.

Find the syntax error