getgrav/grav · error · InvalidArgumentException

Uri path must be a string

Error message

Uri path must be a string

What it means

UriPartsFilter::filterPath() percent-encodes reserved characters in a URI path (without double-encoding existing sequences) and first asserts the input is a string, throwing InvalidArgumentException otherwise. It backs AbstractUri::withPath(), the Uri parts constructor, and Grav\Common\Uri's path helper. Since withPath() declares a native string parameter, the throw mainly fires via direct filterPath() calls or untyped call sites receiving null/array.

Source

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

        throw new InvalidArgumentException('Uri port must be null or an integer between 0 and 65535');
    }

    /**
     * Filter Uri path.
     *
     * This method percent-encodes all reserved characters in the provided path string. This method
     * will NOT double-encode characters that are already percent-encoded.
     *
     * @param  string $path The raw uri path.
     * @return string       The RFC 3986 percent-encoded uri path.
     * @throws InvalidArgumentException If the path is invalid.
     * @link   http://www.faqs.org/rfcs/rfc3986.html
     */
    public static function filterPath($path)
    {
        if (!is_string($path)) {
            throw new InvalidArgumentException('Uri path must be a string');
        }

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

    /**
     * Filters the query string or fragment of a URI.
     *
     * @param string $query The raw uri query string.
     * @return string The percent-encoded query string.
     * @throws InvalidArgumentException If the query is invalid.
     */
    public static function filterQueryOrFragment($query)
    {

View on GitHub (pinned to 6040efed04)

Solutions

  1. Default to an empty path: `$path = $segments[0] ?? ''`
  2. Cast scalars and reject arrays before building URIs
  3. Prefer the typed `$uri->withPath($path)` boundary

Example fix

// before
$path = UriPartsFilter::filterPath($route['path'] ?? null); // null -> throws

// after
$path = UriPartsFilter::filterPath((string) ($route['path'] ?? ''));
Defensive patterns

Strategy: type-guard

Validate before calling

$path = $route['path'] ?? '';
if (!is_string($path)) {
    throw new \InvalidArgumentException('path must be a string');
}

Type guard

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

Prevention

When it happens

Trigger: Calling filterPath(null) when a route/segment lookup returned null; passing an array produced by a path-explode operation; feeding an object (e.g. Stringable) without casting on direct calls.

Common situations: Route builders where an optional path segment config is absent; array_shift() on an already-exhausted segments array yielding null that then flows into the filter.

Related errors


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