yiisoft/yii2 · error · InvalidArgumentException

Password must be a string and cannot be empty.

Error message

Password must be a string and cannot be empty.

What it means

Security::validatePassword() verifies bcrypt hashes and first asserts that the password argument is a non-empty string; null, non-string values, or '' throw InvalidArgumentException before the hash format check and password_verify(). This is strictly about the password argument — a malformed $hash raises the separate 'Hash is invalid.' error instead.

Source

Thrown at framework/base/Security.php:492

        if ($cost === null) {
            $cost = $this->passwordHashCost;
        }

        return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
    }

    /**
     * Verifies a password against a hash.
     * @param string $password The password to verify.
     * @param string $hash The hash to verify the password against.
     * @return bool whether the password is correct.
     * @throws InvalidArgumentException on bad password/hash parameters.
     * @see generatePasswordHash()
     */
    public function validatePassword($password, $hash)
    {
        if (!is_string($password) || $password === '') {
            throw new InvalidArgumentException('Password must be a string and cannot be empty.');
        }

        if (
            !preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches)
            || $matches[1] < 4
            || $matches[1] > 30
        ) {
            throw new InvalidArgumentException('Hash is invalid.');
        }

        return password_verify($password, $hash);
    }

    /**
     * Generates a salt that can be used to generate a password hash.
     *
     * The PHP [crypt()](https://www.php.net/manual/en/function.crypt.php) built-in function
     * requires, for the Blowfish hash algorithm, a salt string in a specific format:

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Handle empty/missing passwords as a failed verification in the caller before invoking Security
  2. Cast genuinely scalar input and bail on emptiness: $password = (string) $input; if ($password === '') return false;
  3. Mark the password attribute required+string in your Model rules so bad input dies at form validation, not inside Security
  4. For API input, reject non-string/empty password fields with a 4xx response at the boundary

Example fix

// before
$ok = Yii::$app->security->validatePassword($model->password ?? null, $user->password_hash);
// null password → InvalidArgumentException

// after
$password = $model->password ?? '';
$ok = $password !== '' && Yii::$app->security->validatePassword($password, $user->password_hash);
Defensive patterns

Strategy: validation

Validate before calling

if (!is_string($password) || $password === '') {
    return false; // empty/missing password is a failed verification, not an exception
}
return Yii::$app->security->validatePassword($password, $hash);

Type guard

function isNonEmptyPassword($password): bool
{
    return is_string($password) && $password !== '';
}

Try / catch

try {
    $ok = Yii::$app->security->validatePassword($password, $hash);
} catch (\InvalidArgumentException $e) {
    // empty/non-string password or invalid hash — treat as failed login and log the argument type, never the value
    $ok = false;
}

Prevention

When it happens

Trigger: validatePassword(null, $hash) when the source attribute is nullable and null-coalesced incorrectly; an optional password field routed straight from request data with '' after trimming; array/scalar-mistyped input forwarded from a wrapper; test fixtures using empty strings.

Common situations: Login or token-verification endpoints that skip their own empty-input validation and call Security directly; nullable database columns feeding the call; API clients omitting the field so it decodes to null.

Related errors


AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17). Data as JSON: /api/errors/775664e10036fd45. Report an issue: GitHub.