{"record":{"id":"e3057c749d1ca56c","repo":"BoundaryML/baml","slug":"failed-to-find-an-available-port-after-attempts","errorCode":null,"errorMessage":"Failed to find an available port after {} attempts","messagePattern":"Failed to find an available port after (.+?) attempts","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/playground-server/src/port_picker.rs","lineNumber":32,"sourceCode":"\npub async fn pick_ports(config: PortConfiguration) -> anyhow::Result<PortPicks> {\n    for playground_port in config.base_port..config.base_port + config.max_attempts {\n        let proxy_port = playground_port + 1;\n\n        if let (Ok(playground_listener), Ok(proxy_listener)) = (\n            TcpListener::bind((\"127.0.0.1\", playground_port)).await,\n            TcpListener::bind((\"127.0.0.1\", proxy_port)).await,\n        ) {\n            return Ok(PortPicks {\n                playground_port,\n                playground_listener,\n                proxy_port,\n                proxy_listener,\n            });\n        }\n    }\n\n    Err(anyhow::anyhow!(\n        \"Failed to find an available port after {} attempts\",\n        config.max_attempts\n    ))\n}\n","sourceCodeStart":14,"sourceCodeEnd":37,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/playground-server/src/port_picker.rs#L14-L37","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check what is holding ports (lsof -i -P -n | grep LISTEN) and stop the conflicting process or the duplicate playground-server instance.","Increase config.max_attempts so the picker can scan a wider range on busy hosts.","Free the ephemeral port range or restart the machine/container if ports are exhausted (TIME_WAIT buildup).","Run the server in an environment with fewer port constraints (fix restrictive network namespaces/security policies blocking binds)."],"exampleFix":"// before\nlet config = PortPickerConfig { start: 3000, max_attempts: 5 };\n// after\nlet config = PortPickerConfig { start: 3000, max_attempts: 100 };","handlingStrategy":"retry","validationCode":"// before starting: check ports are bindable\nfor port in start..start+max_attempts {\n    match std::net::TcpListener::bind((\"127.0.0.1\", port)) {\n        Ok(l) => { drop(l); return Ok(port); }\n        Err(_) => continue,\n    }\n}","typeGuard":null,"tryCatchPattern":"// Rust\nmatch pick_ports(&config) {\n    Ok(ports) => start_server(ports),\n    Err(e) if e.to_string().contains(\"available port\") => {\n        eprintln!(\"Port exhaustion: {}\", e);\n        // free ports or raise max_attempts and retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Raise max_attempts in busy environments","Avoid running multiple playground-server instances on one host","Monitor listening sockets in CI containers","Restart hosts with heavy TIME_WAIT buildup"],"tags":["network","port-allocation","startup","rust"],"backgroundTag":"address-already-in-use","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}