linera-io/linera-protocol · error
Failed to obtain a port
Error message
Failed to obtain a port
What it means
linera-base's get_free_port() asked the OS for a random free TCP port nine times (with growing 1..9s sleeps between attempts) and port_selector::random_free_tcp_port() returned None every time. The helper is only used by tests and dev tooling (test_notification_server, spawn_dummy_indexer/validator, etc.) to grab an ephemeral port for a locally spawned service.
Source
Thrown at linera-base/src/port.rs:20
// SPDX-License-Identifier: Apache-2.0
//! Functionality for obtaining some free port.
use anyhow::{bail, Result};
use port_selector::random_free_tcp_port;
use crate::time::Duration;
/// Provides a port that is currently not used
pub async fn get_free_port() -> Result<u16> {
for i in 1..10 {
let port = random_free_tcp_port();
if let Some(port) = port {
return Ok(port);
}
crate::time::timer::sleep(Duration::from_secs(i)).await;
}
bail!("Failed to obtain a port");
}
/// Provides a local endpoint that is currently available
pub async fn get_free_endpoint() -> Result<String> {
let port = get_free_port().await?;
Ok(format!("127.0.0.1:{port}"))
}
View on GitHub (pinned to 6c226ddcb3)
Solutions
- Raise the file-descriptor limit for the test process: 'ulimit -n 65536' or set LimitNOFILE in the CI runner.
- Kill leaked listeners from previous runs: check 'ss -ltnp' / 'lsof -i' for stray linera processes and terminate them.
- Reduce parallelism of the test run (fewer concurrently spawned validators/indexers) so fewer ports are needed at once.
- Wait/retry the run: TIME_WAIT sockets expire (~60s), freeing the ephemeral range.
Example fix
// before let port = linera_base::port::get_free_port().await?; // Fails when range is exhausted // after (test harness): ensure fd headroom before spawning a fleet // e.g. in CI: ulimit -n 65536; cargo test -- --test-threads=4 // and reuse one helper per suite instead of one port per test where possible.
Defensive patterns
Strategy: retry
Try / catch
// get_free_port already retries internally (9 attempts, backoff); at the harness level:
match linera_base::port::get_free_port().await {
Ok(port) => port,
Err(e) => {
eprintln!("no free port: {e}; check `ulimit -n` and leaked listeners (`ss -ltnp`)");
std::process::exit(1);
}
} Prevention
- Raise nofile limits in CI before running the suite.
- Ensure test harnesses kill spawned validators/indexers on exit (guard with scope/RAII) so ports are released.
- Stagger heavy parallel test jobs to avoid ephemeral-range exhaustion.
When it happens
Trigger: Running the Linera test suite or spawning many dummy validators/indexers on a machine where the ephemeral port range is exhausted (thousands of sockets in TIME_WAIT), the process hit its file-descriptor limit (ulimit -n), or the network stack is otherwise unable to allocate a bindable port.
Common situations: CI runners with low nofile limits running the full integration suite in parallel; a previous test run leaked listeners; heavy TIME_WAIT accumulation after repeated localhost connections; containers with restricted net.core settings.
Related errors
- Expected an `ExecutionError`. Got: {self:#?}
- Expected an `ExecutionError`. Got: {chain_error:#?}
- Invalid address value: {s}
- Invalid blob ID: {s}
- Invalid parsing of GenericApplicationId
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/faa5cdf112a686b4.
Report an issue: GitHub.