vi/websocat · error
Nowhere to connect it
Error message
Nowhere to connect it
What it means
get_only_first_conn is for PeerConstructor variants expected to yield exactly one peer. For ServeMultipleTimes streams it takes the first item of the stream and unwraps it: None means the stream ended without producing any connection at all — there is 'nowhere to connect' the protocol handler — so the library panics instead of yielding a normal error.
Solutions
- Use a connector option that produces a connection (ServeOnce) rather than a listener (ServeMultipleTimes) in this position
- Check why the listener yields zero connections: verify the address/path, permissions, and that a client actually connects
- Turn the expect into a proper error: map the None case to a failed future (e.g. io::Error::new(ErrorKind::BrokenPipe, 'no connection')) so the task ends with a diagnostic
- If this is triggered programmatically, prefer get_only_first_conn only on constructors known to be ServeOnce/Overlay1
Example fix
// before
.map(move |(std_peer, _)| std_peer.expect("Nowhere to connect it"))
// after
.map(move |(std_peer, _)| std_peer.ok_or_else(|| {
io::Error::new(io::ErrorKind::BrokenPipe, "no connection produced")
})) Defensive patterns
Strategy: validation
Validate before calling
// before relying on get_only_first_conn, ensure the constructor yields a connection
if let PeerConstructor::ServeMultipleTimes(_) = ctor {
eprintln!("listener-style constructor: first connection may never arrive");
} Type guard
fn yields_single_connection(c: &PeerConstructor) -> bool {
matches!(c, PeerConstructor::ServeOnce(_) | PeerConstructor::Overlay1(..))
} Try / catch
// panic in a future poll aborts the task; fence it let res = std::panic::catch_unwind(AssertUnwindSafe(|| connect_first(&ctor)));
Prevention
- Only call get_only_first_conn on constructors that produce exactly one peer
- Verify listeners actually receive a client before relying on the first item
- Check addresses, socket paths, and permissions so accept does not end with zero connections
- Patch the library to convert None into a returned io error instead of panicking
When it happens
Trigger: Using an option whose PeerConstructor is ServeMultipleTimes (a listening connector) in a single-connection context, when the listener produces zero connections before ending — e.g. the listen socket fails to yield a first client, an accept loop terminates immediately, or the underlying fd/pipe produces nothing.
Common situations: Pointing the program at a source that can accept but never receives a client (a named pipe, a unix socket no one connects to) combined with an option restricted to one connection; misusing connect-style logic on a serve-style option; the listener closing due to an early signal or error swallowed upstream.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Assertion failed 193913
- assertion failed 1425
- lint should have caught the missing pkcs12_der option
- Time went backwards
AI-assisted analysis of vi/websocat@3a3574cd2f (2026-09-12).
Data as JSON: /api/errors/abd04a53442fc875.
Report an issue: GitHub.
Appendix: source
Thrown at src/util.rs:61
}),
), // This implementation (without Overlay{1,M} cases)
// causes task to be spawned too late (before establishing ws upgrade)
// when serving clients:
//ServeOnce(x) => ServeOnce(Box::new(x.and_then(f)) as BoxedNewPeerFuture),
//ServeMultipleTimes(s) => {
// ServeMultipleTimes(Box::new(s.and_then(f)) as BoxedNewPeerStream)
//}
}
}
pub fn get_only_first_conn(self, l2r: L2rUser) -> BoxedNewPeerFuture {
use crate::PeerConstructor::*;
match self {
Error(e) => Box::new(futures::future::err(e)) as BoxedNewPeerFuture,
ServeMultipleTimes(stre) => Box::new(
stre.into_future()
.map(move |(std_peer, _)| std_peer.expect("Nowhere to connect it"))
.map_err(|(e, _)| e),
) as BoxedNewPeerFuture,
ServeOnce(futur) => futur,
Overlay1(futur, mapper) => {
Box::new(futur.and_then(move |p| mapper(p, l2r))) as BoxedNewPeerFuture
}
OverlayM(stre, mapper) => Box::new(
stre.into_future()
.map(move |(std_peer, _)| std_peer.expect("Nowhere to connect it"))
.map_err(|(e, _)| e)
.and_then(move |p| mapper(p, l2r)),
) as BoxedNewPeerFuture,
}
}
}
pub fn once(x: BoxedNewPeerFuture) -> PeerConstructor {
PeerConstructor::ServeOnce(x)View on GitHub (pinned to 3a3574cd2f)