ekzhang/bore · error

server error

Error message

server error: {message}

What it means

In `Client::new`, after the client sends `Hello`, the server responded with a `ServerMessage::Error` carrying a free-form `message` string, which is re-raised verbatim as `server error: {message}`. This is a pass-through of any application-level error the bore server reports after the initial handshake (e.g. port allocation failure).

Solutions

  1. Read the `{message}` suffix for the server's specific reason and fix accordingly.
  2. Retry with a different remote port (or omit it to let the server assign one).
  3. Check server logs and port-range configuration (`--min-port`) if requesting specific ports.
  4. Verify the server is healthy/restart it if the error indicates internal failure.

Example fix

// before
bore local 3000 --to bore.example.com --port 22
// after (let server pick an available remote port)
bore local 3000 --to bore.example.com
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe the remote port's availability by handling the error message before final use
// (no client-side pre-check exists; parse the server's reason instead)
let result = Client::new(...).await;
if let Err(e) = &result {
    if let Some(reason) = e.to_string().strip_prefix("server error: ") {
        log::warn!("server rejected tunnel: {reason}");
    }
}

Try / catch

match Client::new(...).await {
    Err(e) if e.to_string().starts_with("server error:") => eprintln!("{}", e), // show server's reason
    other => other,
}

Prevention

When it happens

Trigger: Server rejects the `Hello(port)` request: requested remote port is unavailable/in use, the user is not allowed that port, the local port is invalid per server rules, or a server-internal error occurs during connection setup.

Common situations: Requesting a specific remote port already taken by another tunnel; requesting a privileged or forbidden port blocked by server config (`--min-port`); server at capacity; stale server instance with stale state.

Related errors


AI-assisted analysis of ekzhang/bore@00a735a899 (2026-09-08). Data as JSON: /api/errors/87b4bb4e4bad2b16. Report an issue: GitHub.

Appendix: source

Thrown at src/client.rs:52

impl Client {
    /// Create a new client.
    pub async fn new(
        local_host: &str,
        local_port: u16,
        to: &str,
        port: u16,
        secret: Option<&str>,
    ) -> Result<Self> {
        let mut stream = Delimited::new(connect_with_timeout(to, CONTROL_PORT).await?);
        let auth = secret.map(Authenticator::new);
        if let Some(auth) = &auth {
            auth.client_handshake(&mut stream).await?;
        }

        stream.send(ClientMessage::Hello(port)).await?;
        let remote_port = match stream.recv_timeout().await? {
            Some(ServerMessage::Hello(remote_port)) => remote_port,
            Some(ServerMessage::Error(message)) => bail!("server error: {message}"),
            Some(ServerMessage::Challenge(_)) => {
                bail!("server requires authentication, but no client secret was provided");
            }
            Some(_) => bail!("unexpected initial non-hello message"),
            None => bail!("unexpected EOF"),
        };
        info!(remote_port, "connected to server");
        info!("listening at {to}:{remote_port}");

        Ok(Client {
            conn: Some(stream),
            to: to.to_string(),
            local_host: local_host.to_string(),
            local_port,
            remote_port,
            auth,
        })
    }

View on GitHub (pinned to 00a735a899)