symfony/http-foundation · error · BadRequestException
Invalid URI: A URI cannot contain a backslash.
Error message
Invalid URI: A URI cannot contain a backslash.
What it means
Request::create() rejects any URI containing a backslash that appears before the first '?' or '#'. Backslashes are not valid URI characters but some servers/clients normalize them to '/', which enables path-confusion and filter-bypass attacks; the library therefore fails fast with BadRequestException ('Invalid URI: A URI cannot contain a backslash.') producing HTTP 400.
Solutions
- Replace backslashes with forward slashes in the path before calling Request::create(): str_replace('\\', '/', $uri).
- Encode any literal backslash that must be kept (e.g. in a query value) as %5C, or move it after '?' / '#'.
- Sanitize user-supplied path segments with rawurlencode() per segment instead of interpolating raw paths.
- Catch BadRequestException when the URI originates from untrusted input and return a 400.
Example fix
// before
$request = Request::create('http://example.com/C:\\dir\\file');
// after
$uri = str_replace('\\', '/', 'http://example.com/C:/dir/file');
$request = Request::create($uri); Defensive patterns
Strategy: validation
Validate before calling
function hasNoBackslashInPath(string $uri): bool
{
$i = strpos($uri, '\\');
return false === $i || $i >= strcspn($uri, '?#');
}
if (!hasNoBackslashInPath($uri)) {
$uri = preg_replace('/^(.*?):(\/\/[^?#]*)\\/', '$1:$2/', $uri) ?? $uri; // or reject
} Type guard
function isSlashNormalizedUri(string $uri): bool
{
$path = parse_url($uri, PHP_URL_PATH) ?? '';
return false === strpos($path, '\\');
} Try / catch
try {
$request = Request::create($uri);
} catch (BadRequestException $e) {
if (str_contains($e->getMessage(), 'backslash')) {
$request = Request::create(str_replace('\\', '/', $uri));
} else {
throw $e;
}
} Prevention
- Never build URI paths by concatenating raw filesystem paths — join segments with '/' and rawurlencode() each one
- Normalize Windows-style separators (str_replace('\\', '/', ...)) at the boundary where paths become URLs
- Reject backslashes in user-supplied paths early instead of silently rewriting them
- Keep any intentional literal backslash inside the query string, percent-encoded as %5C
When it happens
Trigger: Calling Request::create() with a URI such as 'http://host\path' or '/foo\bar?x=1' where strpos($uri, '\\') is before strcspn($uri, '?#') (Request.php:407-409). Windows-style path separators in the path portion trigger it; backslashes after '?' or '#' (inside query/fragment) are allowed.
Common situations: Code that builds URIs by concatenating Windows file paths; user input containing \\ Sequences passed through to routing; security tests probing path-normalization bypasses; proxies forwarding raw request targets with backslashes.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Invalid URI: Userinfo is malformed.
- Invalid URI: Host is malformed.
- Invalid URI: A URI cannot contain CR/LF/TAB characters.
- Invalid URI: A URI must not start nor end with ASCII…
- Invalid URI: Scheme is malformed.
AI-assisted analysis of symfony/http-foundation@5aea19cd67 (2026-09-13).
Data as JSON: /api/errors/96523df36fb87d8e.
Report an issue: GitHub.
Appendix: source
Thrown at Request.php:409
$server['REQUEST_METHOD'] = strtoupper($method);
if (($i = strcspn($uri, ':/?#')) && ':' === ($uri[$i] ?? null) && (strspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-.') !== $i || strcspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))) {
throw new BadRequestException('Invalid URI: Scheme is malformed.');
}
if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
throw new BadRequestException('Invalid URI.');
}
$part = ($components['user'] ?? '').':'.($components['pass'] ?? '');
if (':' !== $part && \strlen($part) !== strcspn($part, '[]')) {
throw new BadRequestException('Invalid URI: Userinfo is malformed.');
}
if (($part = $components['host'] ?? '') && !self::isHostValid($part)) {
throw new BadRequestException('Invalid URI: Host is malformed.');
}
if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');
}
if (\strlen($uri) !== strcspn($uri, "\r\n\t")) {
throw new BadRequestException('Invalid URI: A URI cannot contain CR/LF/TAB characters.');
}
if ('' !== $uri && (\ord($uri[0]) <= 32 || \ord($uri[-1]) <= 32)) {
throw new BadRequestException('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.');
}
if (isset($components['host'])) {
$server['SERVER_NAME'] = $components['host'];
$server['HTTP_HOST'] = $components['host'];
}
if (isset($components['scheme'])) {
if ('https' === $components['scheme']) {
$server['HTTPS'] = 'on';
$server['SERVER_PORT'] = 443;
} else {View on GitHub (pinned to 5aea19cd67)