{"record":{"id":"5df89fb0832b871f","repo":"dotnet/yarp","slug":"an-outgoing-http-1-1-upgrade-request-is-required-t","errorCode":null,"errorMessage":"An outgoing HTTP/1.1 Upgrade request is required to proxy this request, but is disallowed by HttpVersionPolicy.","messagePattern":"An outgoing HTTP/1\\.1 Upgrade request is required to proxy this request, but is disallowed by HttpVersionPolicy\\.","errorType":"exception","errorClass":"HttpRequestException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Forwarder/HttpForwarder.cs","lineNumber":414,"sourceCode":"                    outgoingConnect = true;\n                    tryDowngradingH2WsOnFailure = true;\n                    break;\n\n                default:\n                    // Override to use HTTP/1.1, nothing else is supported.\n                    outgoingUpgrade = true;\n                    break;\n            }\n        }\n\n        bool http1IsAllowed = outgoingPolicy == HttpVersionPolicy.RequestVersionOrLower || outgoingVersion.Major == 1;\n\n        if (outgoingUpgrade)\n        {\n            // Can only be done on HTTP/1.1, throw if disallowed by options.\n            if (!http1IsAllowed)\n            {\n                throw new HttpRequestException(isSpdyRequest\n                    ? \"SPDY requests require HTTP/1.1 support, but outbound HTTP/1.1 was disallowed by HttpVersionPolicy.\"\n                    : \"An outgoing HTTP/1.1 Upgrade request is required to proxy this request, but is disallowed by HttpVersionPolicy.\");\n            }\n\n            destinationRequest.Version = HttpVersion.Version11;\n            destinationRequest.VersionPolicy = HttpVersionPolicy.RequestVersionOrLower;\n            destinationRequest.Method = HttpMethod.Get;\n        }\n        else if (outgoingConnect)\n        {\n            // HTTP/2 only (for now).\n            destinationRequest.Version = HttpVersion.Version20;\n            destinationRequest.VersionPolicy = HttpVersionPolicy.RequestVersionExact;\n            destinationRequest.Method = HttpMethod.Connect;\n            destinationRequest.Headers.Protocol = connectProtocol ?? WebSocketName;\n            tryDowngradingH2WsOnFailure &= http1IsAllowed;\n        }\n        else","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Forwarder/HttpForwarder.cs#L396-L432","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — WebSocket upgrade blocked\nvar config = new ForwarderRequestConfig\n{\n    Version = new Version(2, 0),\n    VersionPolicy = HttpVersionPolicy.RequestVersionExact // no HTTP/1.1 fallback\n};\n// after — allows HTTP/1.1 downgrade for WebSocket upgrades\nvar config = new ForwarderRequestConfig\n{\n    Version = new Version(2, 0),\n    VersionPolicy = HttpVersionPolicy.RequestVersionOrLower\n};","handlingStrategy":"validation","validationCode":"// Validate that WebSocket-capable routes allow HTTP/1.1 fallback\nvar version = requestConfig?.Version ?? new Version(2, 0);\nvar policy = requestConfig?.VersionPolicy ?? HttpVersionPolicy.RequestVersionOrLower;\nbool http1Allowed = policy == HttpVersionPolicy.RequestVersionOrLower || version.Major == 1;\nif (!http1Allowed)\n{\n    logger.LogWarning(\"Cluster config blocks WebSocket upgrades (no HTTP/1.1 fallback)\");\n}","typeGuard":"static bool SupportsWebSocketUpgrade(Version? version, HttpVersionPolicy? policy, bool isHttps)\n{\n    var v = version ?? new Version(2, 0);\n    var p = policy ?? HttpVersionPolicy.RequestVersionOrLower;\n    // H2WS via extended CONNECT, or HTTP/1.1 upgrade allowed\n    return (v.Major >= 2 && (p == HttpVersionPolicy.RequestVersionOrLower || isHttps))\n        || p == HttpVersionPolicy.RequestVersionOrLower\n        || v.Major == 1;\n}","tryCatchPattern":"try { await forwarder.SendAsync(context, prefix, client, config, transformer, ct); }\ncatch (HttpRequestException ex) when (ex.Message.Contains(\"Upgrade request is required\"))\n{ context.Response.StatusCode = 502; await context.Response.WriteAsync(\"WebSocket upgrade not supported with current protocol policy\"); }","preventionTips":["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."],"tags":["network","protocol","websocket","http2","upgrade","configuration"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}