seanmonstar/warp · critical

failed to bind to address

Error message

failed to bind to address

What it means

`warp::Server::bind(addr)` awaits `tokio::net::TcpListener::bind(addr)` and `.expect("failed to bind to address")`s the result (src/server.rs:78). If the OS refuses to bind (port already in use, permission denied, invalid address), the server panics at startup instead of returning an error. The docs explicitly recommend using `bind` on a listener + `incoming()` when you need to handle bind failures gracefully.

Solutions

  1. Bind the listener yourself and use `incoming()` so errors are values: `TcpListener::bind(addr).await?` then `warp::serve(routes).incoming(listener)`
  2. Check what occupies the port (`lsof -i :3030` / `ss -ltnp`) and stop it or pick a free port
  3. On Linux enable SO_REUSEADDR semantics via your own listener setup (socket2 crate) if TIME_WAIT reuse is the issue
  4. Use an unprivileged port (>=1024) or run with proper capabilities when binding low ports

Example fix

// before
warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
// after
let listener = tokio::net::TcpListener::bind(([127, 0, 0, 1], 3030))
    .await
    .map_err(|e| eprintln!("failed to bind: {e}"))?;
warp::serve(routes).incoming(listener).await;
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting the server, check the port is free:
async fn port_free(addr: std::net::SocketAddr) -> bool {
    tokio::net::TcpListener::bind(addr).await.is_ok()
}

Try / catch

let listener = tokio::net::TcpListener::bind(addr)
    .await
    .map_err(|e| { eprintln!("bind {addr} failed: {e}"); e })?;
warp::serve(routes).incoming(listener).await;

Prevention

When it happens

Trigger: Starting the server with `warp::serve(routes).run(([127,0,0,1],3030))`/`bind((addr, port))` when the port is already taken by another process, the port is privileged (<1024) without root, or the interface address doesn't exist on the host.

Common situations: Two dev servers running concurrently; a previous instance that didn't release the port (crashed process, lingering container); deploying to a platform where PORT is privileged or already bound; typo'd or broadcast/unassigned listen addresses in config.

Related errors


AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09). Data as JSON: /api/errors/f05a27ee68f15600. Report an issue: GitHub.

Appendix: source

Thrown at src/server.rs:78

    /// Panics if we are unable to bind to the provided address.
    ///
    /// To handle bind failures, bind a listener and call `incoming()`.
    pub async fn run(self, addr: impl Into<SocketAddr>) {
        self.bind(addr).await.run().await;
    }

    /// Binds this server.
    ///
    /// # Panics
    ///
    /// Panics if we are unable to bind to the provided address.
    ///
    /// To handle bind failures, bind a listener and call `incoming()`.
    pub async fn bind(self, addr: impl Into<SocketAddr>) -> Server<F, tokio::net::TcpListener, R> {
        let addr = addr.into();
        let acceptor = tokio::net::TcpListener::bind(addr)
            .await
            .expect("failed to bind to address");

        self.incoming(acceptor)
    }

    /// Configure the server with an acceptor of incoming connections.
    pub fn incoming<A>(self, acceptor: A) -> Server<F, A, R> {
        Server {
            acceptor,
            filter: self.filter,
            pipeline: self.pipeline,
            runner: self.runner,
        }
    }

    // pub fn conn
}

impl<F, A, R> Server<F, A, R>

View on GitHub (pinned to ff34d7213e)