getgrav/grav · error · InvalidArgumentException
Uri scheme must be a string
Error message
Uri scheme must be a string
What it means
UriPartsFilter::filterScheme() asserts its argument is a string before lowercasing it, throwing InvalidArgumentException otherwise. It is called from AbstractUri::withScheme() and from the Uri parts constructor. Note that withScheme() declares a native `string $scheme` parameter, so through that path PHP itself usually raises a TypeError first; this exception surfaces mainly on direct filterScheme() calls or untyped call sites.
Source
Thrown at system/src/Grav/Framework/Uri/UriPartsFilter.php:32
use function is_string;
/**
* Class Uri
* @package Grav\Framework\Uri
*/
class UriPartsFilter
{
const HOSTNAME_REGEX = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/u';
/**
* @param string $scheme
* @return string
* @throws InvalidArgumentException If the scheme is invalid.
*/
public static function filterScheme($scheme)
{
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');
}
View on GitHub (pinned to 6040efed04)
Solutions
- Default the value before passing: `$scheme = $config['scheme'] ?? 'https'`
- Cast scalars to string; reject arrays/objects explicitly
- Prefer the typed API `$uri->withScheme('https')` over calling the filter directly
Example fix
// before $scheme = $settings['scheme']; // missing key -> null $new = $uri->withScheme(UriPartsFilter::filterScheme($scheme)); // after $scheme = $settings['scheme'] ?? 'https'; $new = $uri->withScheme((string) $scheme);
Defensive patterns
Strategy: type-guard
Validate before calling
$scheme = $config['scheme'] ?? 'https';
if (!is_string($scheme)) {
throw new \InvalidArgumentException('scheme must be a string');
} Type guard
function isSchemeString(mixed $value): bool
{
return is_string($value) && preg_match('/^[a-z][a-z0-9+.-]*$/i', $value) === 1;
} Prevention
- Default config-derived scheme values before passing them on ($config['scheme'] ?? 'https')
- Prefer the typed $uri->withScheme() API over calling UriPartsFilter directly
- Reject array input at the request boundary for fields destined for URI building
When it happens
Trigger: Calling UriPartsFilter::filterScheme(null) directly; passing a config value that is null/int because the key was missing (`$config->get('scheme')` returning null); building a Uri from a hand-assembled parts array where 'scheme' holds a non-string.
Common situations: Code reading optional scheme settings from YAML/config without a default; arrays built from heterogeneous data passed to Uri::createFromString/UriFactory::createFromParts paths.
Related errors
- URL must be a string
- Uri user info must be a string
- Uri host must be a string
- Uri port must be null or an integer between 0 and 65535
- Uri path must be a string
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/d91762ca997ef540.
Report an issue: GitHub.