getgrav/grav · error · InvalidArgumentException

Uri user info must be a string

Error message

Uri user info must be a string

What it means

UriPartsFilter::filterUserInfo() percent-encodes the user/password component and asserts the input is a string, throwing InvalidArgumentException otherwise. It backs AbstractUri::withUserInfo() and Grav\Common\Uri's user-info helper (which already null-guards). Because withUserInfo() declares native string parameters, this exception effectively fires only on direct filterUserInfo() calls with a non-string, non-null value.

Source

Thrown at system/src/Grav/Framework/Uri/UriPartsFilter.php:48

    {
        if (!is_string($scheme)) {
            throw new InvalidArgumentException('Uri scheme must be a string');
        }

        return strtolower($scheme);
    }

    /**
     * Filters the user info string.
     *
     * @param string $info The raw user or password.
     * @return string The percent-encoded user or password string.
     * @throws InvalidArgumentException
     */
    public static function filterUserInfo($info)
    {
        if (!is_string($info)) {
            throw new InvalidArgumentException('Uri user info must be a string');
        }

        return preg_replace_callback(
            '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=]+|%(?![A-Fa-f0-9]{2}))/u',
            fn($match) => rawurlencode((string) $match[0]),
            $info
        ) ?? '';
    }

    /**
     * @param string $host
     * @return string
     * @throws InvalidArgumentException If the host is invalid.
     */
    public static function filterHost($host)
    {
        if (!is_string($host)) {
            throw new InvalidArgumentException('Uri host must be a string');

View on GitHub (pinned to 6040efed04)

Solutions

  1. Pass the string form: `(string) $username` after confirming it is scalar
  2. Use the typed `$uri->withUserInfo($user, $pass)` API, which coerces earlier and fails with a clearer TypeError
  3. Null-check before calling if the field is optional

Example fix

// before
$user = UriPartsFilter::filterUserInfo($row['user_id']); // int 42 -> throws

// after
$user = UriPartsFilter::filterUserInfo((string) $row['username']);
Defensive patterns

Strategy: type-guard

Validate before calling

$user = is_scalar($authUser) ? (string) $authUser : '';

Type guard

function isUserInfoString(mixed $value): bool
{
    return is_string($value);
}

Prevention

When it happens

Trigger: Calling UriPartsFilter::filterUserInfo() directly with an int/array (e.g. user id from a database instead of the username string); userinfo extracted from a hand-parsed URL where the user segment was captured as an array by a greedy regex.

Common situations: Proxy/auth middleware building a URI from database or header fields where a numeric user id or array sneaks into the username slot.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/66426eaa8ec50190. Report an issue: GitHub.