rustdesk/rustdesk-server · error

Invalid port

Error message

Invalid port

What it means

hbbs validates the `--port` CLI argument after parsing it as i32; any value below 3 is rejected with this anyhow bail. Ports 0-2 are reserved system ports that a rendezvous server must never bind, so the process refuses to start rather than fail later at socket bind time. This is a fail-fast guard at startup in src/main.rs.

Solutions

  1. Pass a valid unprivileged port >= 3, e.g. --port 21116 (the default RENDEZVOUS_PORT).
  2. Check container/orchestrator env: if port comes from an env var, verify it is non-empty and numeric and >= 3 before launching hbbs.
  3. If you intended dynamic port assignment, pick a concrete port instead - hbbs does not support port 0 auto-selection.

Example fix

// before
hbbs --port 0
// after
hbbs --port 21116
Defensive patterns

Strategy: validation

Validate before calling

let port: i32 = std::env::var("HBBS_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(21116);
assert!(port >= 3, "hbbs port must be >= 3, got {port}");

Type guard

fn is_valid_port(p: i32) -> bool { p >= 3 && p <= 65535 }

Prevention

When it happens

Trigger: Running `hbbs --port 0`, `--port 1`, or `--port 2` (or supplying `port` via the arg input the get_arg_or wrapper reads). Any parsed i32 < 3 triggers the bail before RendezvousServer::start_with_bind is called.

Common situations: Operators copying a config file where port was left at 0 to mean 'auto-assign'; docker-compose entries passing PORT=0 expecting dynamic allocation; typos like `--port 2` when intending 21116; scripts using port 1/2 for internal tests against hbbs.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


AI-assisted analysis of rustdesk/rustdesk-server@a7736be5e4 (2026-09-09). Data as JSON: /api/errors/51b41bf24162c548. Report an issue: GitHub.

Appendix: source

Thrown at src/main.rs:31

        .format(opt_format)
        .write_mode(WriteMode::Async)
        .start()?;
    let args = format!(
        "-c --config=[FILE] +takes_value 'Sets a custom config file'
        -b, --bind=[IP] 'Sets the IP address to bind to (default: all interfaces)'
        -p, --port=[NUMBER(default={RENDEZVOUS_PORT})] 'Sets the listening port'
        -s, --serial=[NUMBER(default=0)] '[DEPRECATED] Sets configure update serial number'
        -R, --rendezvous-servers=[HOSTS] '[DEPRECATED] Sets rendezvous servers, separated by comma'
        -u, --software-url=[URL] '[DEPRECATED] Sets download url of RustDesk software of newest version'
        -r, --relay-servers=[HOST] 'Sets the default relay servers, separated by comma'
        -M, --rmem=[NUMBER(default={RMEM})] 'Sets UDP recv buffer size, set system rmem_max first, e.g., sudo sysctl -w net.core.rmem_max=52428800. vi /etc/sysctl.conf, net.core.rmem_max=52428800, sudo sysctl –p'
        , --mask=[MASK] '[DEPRECATED] Determine if the connection comes from LAN, e.g. 192.168.0.0/16'
        -k, --key=[KEY] 'Only allow the client with the same key'",
    );
    init_args(&args, "hbbs", "RustDesk ID/Rendezvous Server");
    let port = get_arg_or("port", RENDEZVOUS_PORT.to_string()).parse::<i32>()?;
    if port < 3 {
        bail!("Invalid port");
    }
    let bind_addr = parse_bind_address(&get_arg("bind"))?;
    let rmem = get_arg("rmem").parse::<usize>().unwrap_or(RMEM);
    let serial: i32 = get_arg("serial").parse().unwrap_or(0);
    crate::common::check_software_update();
    RendezvousServer::start_with_bind(
        bind_addr,
        port,
        serial,
        &get_arg_or("key", "-".to_owned()),
        rmem,
    )?;
    Ok(())
}

View on GitHub (pinned to a7736be5e4)