Soft2Soft Dev Practical knowledge base
PHP

PHP TypeError: Argument Must Be of Type String, Null Given — How to Find and Fix the Cause

13 views
PHP TypeError диагностика ошибок

What Does TypeError: Argument Must Be of Type String, Null Given Mean?

An error such as TypeError: Argument #1 must be of type string, null given occurs when a function or method declares a parameter of type string but actually receives null. This is not a problem with the string itself or a PHP malfunction: the interpreter is reporting a type contract violation. The practical task is not to hide the exception, but to find where the required string value was lost or never assigned.

A typical example:

function normalizeEmail(string $email): string
{
    return strtolower(trim($email));
}
$email = $_POST['email'] ?? null;
$result = normalizeEmail($email);

If the email field is missing from the request, the variable receives null, and the call ends with a TypeError before the function body is executed.

How to Read the Error Message

The full message usually includes the function name, argument number, expected and actual types, and the file and line where the call occurred. It is usually best to start the investigation at the call site rather than at the method declaration.

Message fragmentWhat it indicates
Argument #1The problem is in the first argument passed to the function
must be of type stringThe signature requires a string
null givenAt runtime, null was passed
called in ... on line ...The location where the invalid call was made

If the exception has passed through several application layers, inspect the stack trace from the top down until you reach the first file from your own project. Framework or library frames often only pass control along, while the source of the invalid value is located in a controller, service, form handler, or repository.

Step-by-Step Diagnosis

1. Check the Value Immediately Before the Call

Temporarily record the variable’s type and value. In a production application, it is safer to write diagnostic data to a log instead of displaying it to the visitor.

error_log('email type: ' . get_debug_type($email));
error_log('email is null: ' . ($email === null ? 'yes' : 'no'));
$result = normalizeEmail($email);

Do not log passwords, tokens, full payment details, or other secrets. For user-provided fields, the type, an empty-value indicator, and an operation identifier are often sufficient.

2. Find the Source of null

A null value usually appears in one of the following places:

  • a missing array key or HTTP request parameter;
  • a database field that allows NULL;
  • a lookup method that did not find a record;
  • an optional object property;
  • the result of decoding or transforming input data;
  • a variable assigned only in one branch of a condition.

Do not inspect only the last line. For example, the ?? null operator makes code shorter, but it does not turn a missing value into a valid string.

3. Determine the Business Meaning of the Parameter

Before fixing the code, decide whether the value is allowed to be absent. The method signature and program behavior depend on the answer:

  • if the string is required, validate the data and stop the operation with a clear error;
  • if the value is optional, the parameter should be nullable and the code must handle null;
  • if an empty string is valid, it can be used as the default value, but only when that matches the application logic.

Automatically replacing every null with '' often hides a data problem. For an email address, file path, class name, or identifier, an empty string is usually just as invalid as null.

Practical Ways to Fix the Error

Option 1. Required Field: Validate Before the Call

For a required value, check its presence and format before passing it to a typed method.

$email = $_POST['email'] ?? null;
if (!is_string($email) || trim($email) === '') {
throw new InvalidArgumentException('Поле email обязательно');
}
$result = normalizeEmail($email);

This approach preserves the strict signature and raises the error at a clear application layer. In a web form, the exception is usually replaced with a validation error and the form is returned to the user.

Option 2. Optional Field: Use a Nullable Type

When the value may legitimately be absent, the method contract should reflect that.

function normalizeMiddleName(?string $name): ?string
{
    if ($name === null) {
        return null;
    }
$name = trim($name);
return $name === '' ? null : $name;
}

A nullable signature does not eliminate the need for handling. It only allows null to be passed; the subsequent behavior must still be defined explicitly.

Option 3. Default Value

A default value is appropriate for optional settings and labels. Before applying one, make sure that an empty string does not change the meaning of the operation or turn the original problem into a different error.

Option 4. Fix the Database Data

If a nullable column should actually be required, fix both the PHP code and the stored data. First, find rows containing NULL, determine the correct value, update the records, and only then tighten the schema constraint. Do not apply NOT NULL before cleaning up the existing data.

SELECT id, email
FROM users
WHERE email IS NULL;

After the migration, the application should still validate input data: a database constraint protects storage integrity, but it does not replace clear error handling.

Errors When Working with Arrays and JSON

Missing Array Key

An isset() check returns false both for a missing key and for a key whose value is null. If these situations have different meanings, use array_key_exists().

$payload = ['name' => null];
var_dump(isset($payload['name']));             // false
var_dump(array_key_exists('name', $payload)); // true

Invalid JSON

After decoding incoming JSON, check for errors and validate the result structure before reading any fields.

try {
    $data = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    throw new InvalidArgumentException('Некорректный JSON', 0, $e);
}
if (!is_array($data)) {
throw new InvalidArgumentException('Ожидался JSON-объект');
}
$name = $data['name'] ?? null;
if (!is_string($name) || trim($name) === '') {
throw new InvalidArgumentException('Поле name обязательно');
}

Why Type Casting Does Not Always Solve the Problem

The (string) $value construct converts null to an empty string. The TypeError disappears, but the data may still be invalid.

$email = (string) ($_POST['email'] ?? null);
$result = normalizeEmail($email);

This approach is acceptable only when an empty string is an officially supported result. For required fields, strict validation is preferable. You should also avoid suppressing errors with the @ operator: it does not restore missing data and makes diagnosis less transparent.

Verifying the Fix

After changing the code, test more than the successful scenario. The minimum test set should include:

  1. a valid non-empty string;
  2. a missing field;
  3. an explicit null value;
  4. an empty string and a whitespace-only string;
  5. a value of another type, such as an array or number;
  6. a database record containing NULL, if the data source allows it.

Quick Checklist

  • open the file and call-site line shown in the stack trace;
  • check the actual argument type with get_debug_type();
  • trace the value back to the request, database, or lookup method;
  • decide whether the parameter is required, nullable, or has a default value;
  • do not replace null with an empty string without checking the business logic;
  • add validation at the system boundary;
  • align the constraints in the PHP code with the database schema;
  • test a missing field, null, an empty string, and an invalid type;
  • remove temporary diagnostics or keep only safe logging.

A reliable TypeError fix preserves the method’s strict contract and eliminates the source of the invalid value. The error then becomes either controlled validation or correctly supported nullable behavior instead of being hidden by an arbitrary type cast.