quickwit-oss/quickwit · critical

err

Error message

err

What it means

Quickwit's server startup binds its TCP listener through the TcpListenerResolver abstraction. The default resolver wraps the std Tokio bind result, converting any bind failure (address in use, permission denied, invalid address) into an anyhow error. The message is just `err`, so the underlying OS error text carries the real cause.

Solutions

  1. Check what occupies the port (ss -ltnp / lsof -i :PORT) and stop it or choose another port.
  2. Change the listen_address port in the Quickwit node config or via the --listen-address CLI flag.
  3. If binding a privileged port, run with the required capability or use a high port behind a proxy.
  4. Verify the configured address is assigned to the machine (avoid hardcoded external IPs inside containers).

Example fix

// before (config)
listen_address: 0.0.0.0
rest_listen_port: 7280 // already in use
// after
rest_listen_port: 7281
Defensive patterns

Strategy: try-catch

Validate before calling

fn port_free(addr: SocketAddr) -> bool {
    std::net::TcpListener::bind(addr).is_ok()
}

Try / catch

loop {
    match server.bind(listen_addr).await {
        Ok(srv) => break srv.serve().await,
        Err(e) if e.to_string().contains("Address already in use") => {
            eprintln!("port in use, retrying in 2s...");
            tokio::time::sleep(Duration::from_secs(2)).await;
        }
        Err(e) => return Err(e.into()),
    }
}

Prevention

When it happens

Trigger: Starting the Quickwit server (rest/grpc listen address) when TcpListener::bind fails: port already occupied, binding to a privileged port without permissions, or binding to an address not assigned to the host.

Common situations: Another Quickwit instance or different service already listening on the port; Docker/Kubernetes port conflicts; running in a container without CAP_NET_BIND_SERVICE while binding port <1024; typo'd listen_address in config.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/29e7bfddf0d1df3f. Report an issue: GitHub.

Appendix: source

Thrown at quickwit/quickwit-serve/src/tcp_listener.rs:38

/// Resolve `SocketAddr` into `TcpListener` instances.
///
/// This trait can be used to inject existing [`TcpListener`] instances to the
/// Quickwit REST and gRPC servers when running them in tests.
#[async_trait]
pub trait TcpListenerResolver: Clone + Send + 'static {
    async fn resolve(&self, addr: SocketAddr) -> anyhow::Result<TcpListener>;
}

#[derive(Clone)]
pub struct DefaultTcpListenerResolver;

#[async_trait]
impl TcpListenerResolver for DefaultTcpListenerResolver {
    async fn resolve(&self, addr: SocketAddr) -> anyhow::Result<TcpListener> {
        TcpListener::bind(addr)
            .await
            .map_err(|err| anyhow::anyhow!(err))
    }
}

#[cfg(any(test, feature = "testsuite"))]
pub mod for_tests {
    use std::collections::HashMap;
    use std::sync::Arc;

    use anyhow::Context;
    use tokio::sync::Mutex;

    use super::*;

    #[derive(Clone, Default)]
    pub struct TestTcpListenerResolver {
        listeners: Arc<Mutex<HashMap<SocketAddr, TcpListener>>>,
    }

View on GitHub (pinned to a39730c5cd)