dotnet/yarp · error · HttpRequestException
An outgoing HTTP/1.1 Upgrade request is required to proxy th
Error message
An outgoing HTTP/1.1 Upgrade request is required to proxy this request, but is disallowed by HttpVersionPolicy.
What it means
WebSocket (and other non-SPDY) upgrade requests that cannot use HTTP/2 extended CONNECT fall back to a classic HTTP/1.1 Upgrade handshake. If the outgoing protocol policy disallows HTTP/1.1, YARP cannot proxy the WebSocket connection and throws this HttpRequestException. The decision tree in CreateRequestMessageAsync selects `outgoingUpgrade = true` for the HTTP/1.1 fallback path, then checks the same `http1IsAllowed` gate.
Source
Thrown at src/ReverseProxy/Forwarder/HttpForwarder.cs:414
outgoingConnect = true;
tryDowngradingH2WsOnFailure = true;
break;
default:
// Override to use HTTP/1.1, nothing else is supported.
outgoingUpgrade = true;
break;
}
}
bool http1IsAllowed = outgoingPolicy == HttpVersionPolicy.RequestVersionOrLower || outgoingVersion.Major == 1;
if (outgoingUpgrade)
{
// Can only be done on HTTP/1.1, throw if disallowed by options.
if (!http1IsAllowed)
{
throw new HttpRequestException(isSpdyRequest
? "SPDY requests require HTTP/1.1 support, but outbound HTTP/1.1 was disallowed by HttpVersionPolicy."
: "An outgoing HTTP/1.1 Upgrade request is required to proxy this request, but is disallowed by HttpVersionPolicy.");
}
destinationRequest.Version = HttpVersion.Version11;
destinationRequest.VersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
destinationRequest.Method = HttpMethod.Get;
}
else if (outgoingConnect)
{
// HTTP/2 only (for now).
destinationRequest.Version = HttpVersion.Version20;
destinationRequest.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
destinationRequest.Method = HttpMethod.Connect;
destinationRequest.Headers.Protocol = connectProtocol ?? WebSocketName;
tryDowngradingH2WsOnFailure &= http1IsAllowed;
}
elseView on GitHub (pinned to bd11867bee)
Solutions
- Set `VersionPolicy` to `RequestVersionOrLower` so YARP can downgrade to HTTP/1.1 for WebSocket upgrade requests.
- If using HTTPS to the destination, ensure the version/policy combo selects the H2WS extended-CONNECT path instead (e.g., Version=2 + RequestVersionOrLower with `https://` destination prefix).
- Remove the Version/VersionPolicy override entirely so defaults apply (RequestVersionOrLower, which permits HTTP/1.1).
- Switch the destination prefix from `http://` to `https://` if the backend supports HTTP/2 WebSockets over TLS.
Example fix
// before — WebSocket upgrade blocked
var config = new ForwarderRequestConfig
{
Version = new Version(2, 0),
VersionPolicy = HttpVersionPolicy.RequestVersionExact // no HTTP/1.1 fallback
};
// after — allows HTTP/1.1 downgrade for WebSocket upgrades
var config = new ForwarderRequestConfig
{
Version = new Version(2, 0),
VersionPolicy = HttpVersionPolicy.RequestVersionOrLower
}; Defensive patterns
Strategy: validation
Validate before calling
// Validate that WebSocket-capable routes allow HTTP/1.1 fallback
var version = requestConfig?.Version ?? new Version(2, 0);
var policy = requestConfig?.VersionPolicy ?? HttpVersionPolicy.RequestVersionOrLower;
bool http1Allowed = policy == HttpVersionPolicy.RequestVersionOrLower || version.Major == 1;
if (!http1Allowed)
{
logger.LogWarning("Cluster config blocks WebSocket upgrades (no HTTP/1.1 fallback)");
} Type guard
static bool SupportsWebSocketUpgrade(Version? version, HttpVersionPolicy? policy, bool isHttps)
{
var v = version ?? new Version(2, 0);
var p = policy ?? HttpVersionPolicy.RequestVersionOrLower;
// H2WS via extended CONNECT, or HTTP/1.1 upgrade allowed
return (v.Major >= 2 && (p == HttpVersionPolicy.RequestVersionOrLower || isHttps))
|| p == HttpVersionPolicy.RequestVersionOrLower
|| v.Major == 1;
} Try / catch
try { await forwarder.SendAsync(context, prefix, client, config, transformer, ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("Upgrade request is required"))
{ context.Response.StatusCode = 502; await context.Response.WriteAsync("WebSocket upgrade not supported with current protocol policy"); } Prevention
- For WebSocket routes, always use RequestVersionOrLower or ensure the destination is HTTPS with HTTP/2 support.
- Test WebSocket connectivity after changing Version or VersionPolicy on a cluster.
- Avoid RequestVersionExact for clusters serving mixed HTTP/1.1 and WebSocket traffic.
When it happens
Trigger: An incoming WebSocket upgrade request (`IHttpUpgradeFeature.IsUpgradableRequest` with `Upgrade: websocket`) reaches a cluster whose Version/VersionPolicy combination routes to the `default` case of the WebSocket switch (lines 400-404), setting `outgoingUpgrade = true`. Simultaneously the policy forbids HTTP/1.1 (`outgoingPolicy != RequestVersionOrLower && outgoingVersion.Major != 1`). For example: Version=2.0, VersionPolicy=RequestVersionExact, and a non-HTTPS destination prefix.
Common situations: A developer configures a cluster to use HTTP/2 over plain HTTP (`http://`) with `RequestVersionExact` for performance, not realizing this blocks WebSocket upgrades. Or an operator sets `RequestVersionOrHigher` with HTTP/2 for a plain-HTTP backend that doesn't support HTTP/2 extended CONNECT for WebSockets.
Related errors
- SPDY requests require HTTP/1.1 support, but outbound HTTP/1.
- Configuration Filter Error: Substitution for '{lookup}' in c
- A non-empty CustomTransform value is required
- A non-empty CustomMetadata value is required
- The route config format has changed, routes are now objects
AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13).
Data as JSON: /api/errors/5df89fb0832b871f.
Report an issue: GitHub.