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

  1. Use a connector option that produces a connection (ServeOnce) rather than a listener (ServeMultipleTimes) in this position
  2. Check why the listener yields zero connections: verify the address/path, permissions, and that a client actually connects
  3. 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
  4. 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

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


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)