BoundaryML/baml · error

Failed to find an available port after

Error message

Failed to find an available port after {} attempts

What it means

The playground server's pick_ports function scans for free TCP ports by binding a listener on port 0 and retrying. After exhausting config.max_attempts tries without finding an available port for the server/proxy pair, it gives up and returns this anyhow error. It is a fail-fast guard so startup cannot proceed with unusable ports.

Solutions

  1. Check what is holding ports (lsof -i -P -n | grep LISTEN) and stop the conflicting process or the duplicate playground-server instance.
  2. Increase config.max_attempts so the picker can scan a wider range on busy hosts.
  3. Free the ephemeral port range or restart the machine/container if ports are exhausted (TIME_WAIT buildup).
  4. Run the server in an environment with fewer port constraints (fix restrictive network namespaces/security policies blocking binds).

Example fix

// before
let config = PortPickerConfig { start: 3000, max_attempts: 5 };
// after
let config = PortPickerConfig { start: 3000, max_attempts: 100 };
Defensive patterns

Strategy: retry

Validate before calling

// before starting: check ports are bindable
for port in start..start+max_attempts {
    match std::net::TcpListener::bind(("127.0.0.1", port)) {
        Ok(l) => { drop(l); return Ok(port); }
        Err(_) => continue,
    }
}

Try / catch

// Rust
match pick_ports(&config) {
    Ok(ports) => start_server(ports),
    Err(e) if e.to_string().contains("available port") => {
        eprintln!("Port exhaustion: {}", e);
        // free ports or raise max_attempts and retry
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: pick_ports is called at playground-server startup and every candidate port it tries is occupied (or binding fails), until config.max_attempts is exhausted.

Common situations: Running the playground server while many dev servers occupy the high port range; a crowded container/CI host with ephemeral port exhaustion; a misconfigured max_attempts that is too low (e.g. 1-10) on a busy machine; another instance of the same server already running and holding the ports.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/e3057c749d1ca56c. Report an issue: GitHub.

Appendix: source

Thrown at engine/playground-server/src/port_picker.rs:32

pub async fn pick_ports(config: PortConfiguration) -> anyhow::Result<PortPicks> {
    for playground_port in config.base_port..config.base_port + config.max_attempts {
        let proxy_port = playground_port + 1;

        if let (Ok(playground_listener), Ok(proxy_listener)) = (
            TcpListener::bind(("127.0.0.1", playground_port)).await,
            TcpListener::bind(("127.0.0.1", proxy_port)).await,
        ) {
            return Ok(PortPicks {
                playground_port,
                playground_listener,
                proxy_port,
                proxy_listener,
            });
        }
    }

    Err(anyhow::anyhow!(
        "Failed to find an available port after {} attempts",
        config.max_attempts
    ))
}

View on GitHub (pinned to bd85ce9dee)