Fix PHP json_decode() Error: 'expects parameter 1 to be string, null given'

beginner๐Ÿ˜ PHP2026-03-23| PHP 7.x / 8.x, any OS (Linux, macOS, Windows), any framework (Laravel, Symfony, plain PHP)

Error Message

json_decode() expects parameter 1 to be string, null given
#php#json#decode#parse

The Error

You call json_decode() and get slapped with:

json_decode() expects parameter 1 to be string, null given

Or on PHP 8:

json_decode(): Argument #1 ($json) must be of type string, null given

The function got null instead of a JSON string. The crash line is obvious โ€” the real problem is hiding a few lines above it.

Root Causes

  • An API response or file read returned null or empty, and you passed it straight to json_decode() without checking. This is the most common cause.
  • A function you expected to return a string actually returns null on failure โ€” file_get_contents(), $request->getContent(), and DB column reads all do this silently.
  • The variable was never assigned โ€” a typo in the variable name, a missing assignment, or a conditional branch that skipped it entirely.
  • JSON came from user input or an external service that sent nothing: empty POST body, missing query param, or a 4xx response with no body.

Fix 1 โ€” Guard Before Decoding

Check that the value is a non-empty string before you even touch json_decode(). Simple, and it forces you to decide what "failure" means for your code.

<?php

$raw = file_get_contents('https://api.example.com/data');

if ($raw === false || $raw === null || $raw === '') {
    // Log it, throw an exception, return early โ€” pick one
    throw new RuntimeException('Failed to fetch JSON data');
}

$data = json_decode($raw, true);

With user input from a request:

<?php

$body = $request->getContent(); // Could be an empty string

if (empty($body)) {
    return response()->json(['error' => 'Empty request body'], 400);
}

$data = json_decode($body, true);

Fix 2 โ€” Check json_last_error() After Decoding

Here's a trap: json_decode() returns null for two very different situations โ€” the input was null, and the JSON was malformed. Without checking, you can't tell which one happened.

<?php

$data = json_decode($raw, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    throw new RuntimeException('JSON decode failed: ' . json_last_error_msg());
}

This catches invalid syntax, unexpected encoding, and truncated responses โ€” failures that would otherwise slip through silently and corrupt your data downstream.

Fix 3 โ€” Null Coalescing for Optional Data

Sometimes a missing value is perfectly normal โ€” a nullable DB column, an optional config field. In that case, provide a safe fallback instead of bailing out:

<?php

// If $row['metadata'] is null, decode an empty object instead
$metadata = json_decode($row['metadata'] ?? '{}', true);

// Or for an array
$tags = json_decode($row['tags'] ?? '[]', true);

Pick a fallback that actually makes sense for your data. Defaulting back to null defeats the purpose.

Fix 4 โ€” Trace Where null Comes From

When the source isn't obvious, dump the value right before the decode and kill execution:

<?php

var_dump($raw); // Is it null? false? An empty string?
die();

$data = json_decode($raw, true);

Once you see the actual value, the cause usually becomes clear:

  • file_get_contents() returned false โ€” wrong path, permission denied, or a network timeout
  • $_POST['json_data'] is undefined โ€” wrong field name, or the client sent application/x-www-form-urlencoded instead of application/json
  • DB column is NULL โ€” the row exists but that field was never populated
  • cURL response body is empty โ€” the server returned a 4xx/5xx with no body

For cURL specifically, check the HTTP status code too โ€” a 401 or 500 response often has an empty body:

<?php

$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($response === false || $httpCode !== 200) {
    throw new RuntimeException("API request failed with HTTP $httpCode");
}

$data = json_decode($response, true);

Fix 5 โ€” Wrap It in a Helper for Consistent Handling

PHP 8 upgraded this from a warning to a full TypeError, which makes it easier to spot in logs. Either way, if you're decoding JSON in multiple places, centralise it:

<?php

function safe_json_decode(?string $json, bool $assoc = true): mixed
{
    if ($json === null || $json === '') {
        return null;
    }

    $data = json_decode($json, $assoc);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new \InvalidArgumentException('Invalid JSON: ' . json_last_error_msg());
    }

    return $data;
}

Every decode in your codebase now goes through one function. Errors surface immediately with a useful message instead of propagating as mysterious null values three layers deep.

Verify the Fix

Quick sanity check in a scratch file:

<?php

// Should return the array without errors
$result = json_decode('{"key": "value"}', true);
var_dump($result); // array(1) { ["key"] => string(5) "value" }

// Null guard should produce an empty array
$result = json_decode(null ?? '{}', true);
var_dump($result); // array(0) {}

In a Laravel or Symfony app, run your test suite or hit the endpoint directly:

curl -X POST https://yourapp.test/api/endpoint \
  -H 'Content-Type: application/json' \
  -d '{"test": true}'

Also test the unhappy path โ€” send an empty body and confirm your guard returns a proper 400 instead of crashing.

Prevention

The real fix happens upstream, not at the decode call itself. Any JSON coming from an API, a file, or user input should be validated before it touches json_decode(). External services are especially unreliable โ€” they return empty bodies on auth failures, malformed JSON on partial responses, and plain HTML error pages when something breaks on their end.

When debugging malformed JSON, the JSON Formatter & Validator on ToolCraft is worth bookmarking โ€” paste the raw string and it pinpoints the exact syntax error immediately. Runs entirely in your browser, nothing uploaded.

Habits that make this bug nearly impossible to hit:

  • Enable strict types (declare(strict_types=1);) โ€” PHP 8 throws TypeError before reaching json_decode() if you pass the wrong type
  • Use typed class properties โ€” if $this->jsonData is declared as string, assigning null fails at the assignment, not three calls later
  • Log raw responses before decoding during development โ€” you'll catch empty or malformed responses the moment they appear
  • Write unit tests that send null, empty string, and broken JSON to every endpoint that decodes input โ€” make the edge cases explicit

Related Error Notes