BoundaryML/baml · error · anyhow::Error
Could not find an available port in range {}..{}
Error message
Could not find an available port in range {}..{} What it means
pick_port scans up to max_attempts consecutive ports starting at base_port, binding a loopback TcpListener on each until one succeeds. If every candidate port fails to bind, it bails with this anyhow error. It exists so callers can auto-pick a free port starting from the default 4265.
Source
Thrown at baml_language/crates/baml_lsp_server/src/playground_server.rs:401
RunOutcome::Failed(RunError {
class: runtime_error_class(err),
message: format!("{err}"),
details: None,
value_ref,
})
}
/// Find an available TCP port starting from `base_port`.
pub async fn pick_port(base_port: u16, max_attempts: u16) -> anyhow::Result<(TcpListener, u16)> {
for offset in 0..max_attempts {
let port = base_port + offset;
let addr = SocketAddr::from(([127, 0, 0, 1], port));
match TcpListener::bind(addr).await {
Ok(listener) => return Ok((listener, port)),
Err(_) => continue,
}
}
anyhow::bail!(
"Could not find an available port in range {}..{}",
base_port,
base_port + max_attempts
)
}
/// Resolve the given env var names against `lookup`, keeping only those set.
/// Pure so tests never have to mutate the process environment.
fn collect_referenced_env_vars(
names: &[String],
lookup: impl Fn(&str) -> Option<String>,
) -> std::collections::HashMap<String, String> {
names
.iter()
.filter_map(|n| lookup(n).map(|v| (n.clone(), v)))
.collect()
}
View on GitHub (pinned to bd85ce9dee)
Solutions
- Free the occupied ports: find and kill the processes listening in the range (lsof -i :4265-4290).
- Restart the client; pick_port retries and may find a freed port.
- Increase the scan range/max_attempts or start from a different base port via --port.
- Reboot or clean up leaked listeners if orphaned processes hold the ports.
Example fix
// before let (listener, port) = pick_port(4265, 10).await?; // all 10 busy // after let (listener, port) = pick_port(4265, 100).await?; // wider scan range
Defensive patterns
Strategy: retry
Validate before calling
for port in base_port..base_port + max_attempts {
if std::net::TcpListener::bind(("127.0.0.1", port)).is_ok() {
break; // a port is free
}
} Try / catch
match pick_port(4265, 10).await {
Ok((listener, port)) => serve(listener, port),
Err(e) if e.to_string().contains("available port") => {
eprintln!("all candidate ports busy; free ports 4265+ and retry");
}
Err(e) => return Err(e),
} Prevention
- Clean up leaked listeners from crashed sessions (lsof -i :4265)
- Avoid launching many concurrent LSP instances on one machine
- Use a wider scan range when port usage is heavy
When it happens
Trigger: Calling pick_port(base_port, max_attempts) when all ports in base_port..base_port+max_attempts are already bound by other processes (TcpListener::bind fails for each attempt).
Common situations: Many concurrent playground/LSP sessions on one machine exhausting the scanned range; a system service squatting on 4265 and neighbors; very small max_attempts with heavy port usage; leaked listeners from crashed previous runs.
Related errors
- Could not bind playground port {port}: {e}. Another process
- {err}
- Playground server error: {e}
- network error fetching {url}: {source}
- HTTP {status} fetching {url}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/ea7c6d86b965bf17.
Report an issue: GitHub.