seanmonstar/warp · error
websocket handshake thread panicked
Error message
websocket handshake thread panicked
What it means
In warp's test utilities, WsClient handshake awaits the oneshot channel from the spawned handshake thread; if that thread panics (sender dropped), handshake panics with 'websocket handshake thread panicked'. This masks the underlying panic in the filter/service being tested.
Solutions
- Inspect test output for the ORIGINAL panic message in the spawned thread (often printed before this one)
- Fix the panic inside the ws filter/handler (avoid unwrap/assert on request data)
- Ensure the route under test actually applies filters::ws() and accepts the connection
Example fix
// before
let client = ws::handshake().await?; // panics when handler panics
// after
// make the handler fallible instead of panicking:
.and_then(|input| async move {
parse(input).map_err(|e| warp::reject::custom(e))
}) Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the route under test contains the ws filter before handshaking
let route = warp::path("ws").and(warp::ws()); Try / catch
// the panic happens inside warp's spawned thread; use catch_unwind around the test body
let result = std::panic::catch_unwind(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { ws::ws_client().handshake().await })
});
assert!(result.is_ok(), "handshake thread panicked — check filter for panics"); Prevention
- Avoid unwrap/assert/panic inside ws filter handlers — return rejects instead
- Verify the route includes filters::ws() before testing
- Read the earlier panic message from the spawned thread to find the root cause
When it happens
Trigger: Calling .handshake() on a warp test WebSocket client when the ws filter rejects/panics during the upgrade — e.g. an assert! or unwrap inside the filter's closure fails before the upgrade completes.
Common situations: Integration tests where the handler panics on unexpected input, or the route doesn't actually include a ws() filter so the upgrade never happens.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- valid method
- test request path invalid
- polled after complete
- polled after complete
- polled after complete
AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09).
Data as JSON: /api/errors/7c2ae6784395ec10.
Report an issue: GitHub.
Appendix: source
Thrown at src/test.rs:580
.take_while(|result| match result {
Err(_) => future::ready(false),
Ok(m) => future::ready(!m.is_close()),
})
.for_each(move |item| {
rd_tx.unbounded_send(item).expect("ws receive error");
future::ready(())
});
future::join(write, read).await;
});
match upgraded_rx.await {
Ok(Ok(())) => Ok(WsClient {
tx: wr_tx,
rx: rd_rx,
}),
Ok(Err(err)) => Err(WsError::new(err)),
Err(_canceled) => panic!("websocket handshake thread panicked"),
}
}
}
#[cfg(feature = "websocket")]
impl WsClient {
/// Send a "text" websocket message to the server.
pub async fn send_text(&mut self, text: impl Into<String>) {
self.send(crate::ws::Message::text(text.into())).await;
}
/// Send a websocket message to the server.
pub async fn send(&mut self, msg: crate::ws::Message) {
self.tx.unbounded_send(msg).unwrap();
}
/// Receive a websocket message from the server.
pub async fn recv(&mut self) -> Result<crate::filters::ws::Message, WsError> {View on GitHub (pinned to ff34d7213e)