{"record":{"id":"000997b3b10d949f","repo":"seanmonstar/warp","slug":"missingconnectionupgrade","errorCode":null,"errorMessage":"MissingConnectionUpgrade","messagePattern":"MissingConnectionUpgrade","errorType":"http","errorClass":"MissingConnectionUpgrade","httpStatus":400,"severity":"error","filePath":"src/filters/ws.rs","lineNumber":50,"sourceCode":"/// - Header `connection` must be `upgrade`\n/// - Header `upgrade` must be `websocket`\n/// - Header `sec-websocket-version` must be `13`\n/// - Header `sec-websocket-key` must be set.\n///\n/// If the filters are met, yields a `Ws`. Calling `Ws::on_upgrade` will\n/// return a reply with:\n///\n/// - Status of `101 Switching Protocols`\n/// - Header `connection: upgrade`\n/// - Header `upgrade: websocket`\n/// - Header `sec-websocket-accept` with the hash value of the received key.\npub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {\n    let connection_has_upgrade = header::header2()\n        .and_then(|conn: ::headers::Connection| {\n            if conn.contains(\"upgrade\") {\n                future::ok(())\n            } else {\n                future::err(crate::reject::known(MissingConnectionUpgrade))\n            }\n        })\n        .untuple_one();\n\n    crate::get()\n        .and(connection_has_upgrade)\n        .and(header::exact_ignore_case(\"upgrade\", \"websocket\"))\n        .and(header::exact(\"sec-websocket-version\", \"13\"))\n        //.and(header::exact2(Upgrade::websocket()))\n        //.and(header::exact2(SecWebsocketVersion::V13))\n        .and(header::header2::<SecWebsocketKey>())\n        .and(on_upgrade())\n        .map(\n            move |key: SecWebsocketKey, on_upgrade: Option<OnUpgrade>| Ws {\n                config: None,\n                key,\n                on_upgrade,\n            },","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/seanmonstar/warp/blob/ff34d7213ed55ec342304aa7ff6ac4b351da9e66/src/filters/ws.rs#L32-L68","documentation":"warp::ws() (src/filters/ws.rs:50) requires the request to include a Connection header whose value contains \"upgrade\"; otherwise it rejects with MissingConnectionUpgrade. WebSocket handshakes per RFC 6455 must carry Connection: Upgrade alongside Upgrade: websocket, so a request lacking this header cannot begin a WS session.","triggerScenarios":"A request to a warp::ws() route that omits the Connection: upgrade header — typically a plain HTTP request, a client library not setting the header, or an intermediary proxy stripping hop-by-hop Connection headers. Also triggered if the request is not a GET (ws() composes warp::get()).","commonSituations":"Testing the WS endpoint with curl or Postman without WS mode; reverse proxies (older nginx/HAProxy configs) dropping the Connection/Upgrade headers; misconfigured clients hitting the WS route with ordinary fetch/axios instead of a WebSocket client; missing proxy_read_headers / Upgrade forwarding settings.","solutions":["Connect using a real WebSocket client (browser WebSocket API, tokio-tungstenite, etc.) rather than plain HTTP — it sets Connection: Upgrade and Upgrade: websocket automatically","Configure reverse proxies to forward Upgrade and Connection headers (e.g. nginx: proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \"upgrade\")","Ensure the request uses GET, since ws() composes warp::get()","Recover the rejection and return a clear 426 Upgrade Required response for misdirected plain-HTTP requests"],"exampleFix":"// before (nginx)\nlocation /ws {\n    proxy_pass http://backend;\n}\n// -> Connection header stripped -> MissingConnectionUpgrade\n\n// after (nginx)\nlocation /ws {\n    proxy_pass http://backend;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"upgrade\";\n}","handlingStrategy":"validation","validationCode":"// client-side: only open WS endpoints with a WebSocket client that sends upgrade headers\nconst isWsUrl = url.startsWith('ws://') || url.startsWith('wss://');\nif (!isWsUrl) throw new Error(`use a WebSocket client for ${url}, not plain HTTP`);","typeGuard":"function isWebSocketReady(req) {\n  return req.method === 'GET' &&\n    /upgrade/i.test(req.headers.connection || '') &&\n    /websocket/i.test(req.headers.upgrade || '');\n}","tryCatchPattern":"let resp = ws_routes.recover(|rej: warp::Rejection| async move {\n    if !rej.is_not_found() && rej.find::<warp::ws::MissingConnectionUpgrade>().is_some() {\n        Ok(warp::reply::with_status(\"Upgrade Required\", warp::http::StatusCode::UPGRADE_REQUIRED))\n    } else { Err(rej) }\n});","preventionTips":["Use proper WebSocket client libraries, never fetch/axios, for ws:// endpoints","Verify proxy forwarding of Upgrade and Connection headers (proxy_http_version 1.1 in nginx)","Smoke-test the WS handshake in integration tests (e.g. warp::test::ws())","Return 426 Upgrade Required in a recover handler so misconfigured clients get a clear signal"],"tags":["websocket","http","upgrade","headers","warp"],"backgroundTag":"websocket-upgrade-required","analyzedSha":"ff34d7213ed55ec342304aa7ff6ac4b351da9e66","analyzedAt":"2026-09-09T16:57:46.316Z","contentChangedAt":"2026-09-09T16:57:46.316Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}