{"record":{"id":"faa5cdf112a686b4","repo":"linera-io/linera-protocol","slug":"failed-to-obtain-a-port","errorCode":null,"errorMessage":"Failed to obtain a port","messagePattern":"Failed to obtain a port","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-base/src/port.rs","lineNumber":20,"sourceCode":"// SPDX-License-Identifier: Apache-2.0\n\n//! Functionality for obtaining some free port.\n\nuse anyhow::{bail, Result};\nuse port_selector::random_free_tcp_port;\n\nuse crate::time::Duration;\n\n/// Provides a port that is currently not used\npub async fn get_free_port() -> Result<u16> {\n    for i in 1..10 {\n        let port = random_free_tcp_port();\n        if let Some(port) = port {\n            return Ok(port);\n        }\n        crate::time::timer::sleep(Duration::from_secs(i)).await;\n    }\n    bail!(\"Failed to obtain a port\");\n}\n\n/// Provides a local endpoint that is currently available\npub async fn get_free_endpoint() -> Result<String> {\n    let port = get_free_port().await?;\n    Ok(format!(\"127.0.0.1:{port}\"))\n}\n","sourceCodeStart":2,"sourceCodeEnd":28,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-base/src/port.rs#L2-L28","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet port = linera_base::port::get_free_port().await?; // Fails when range is exhausted\n\n// after (test harness): ensure fd headroom before spawning a fleet\n// e.g. in CI: ulimit -n 65536; cargo test -- --test-threads=4\n// and reuse one helper per suite instead of one port per test where possible.","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// get_free_port already retries internally (9 attempts, backoff); at the harness level:\nmatch linera_base::port::get_free_port().await {\n    Ok(port) => port,\n    Err(e) => {\n        eprintln!(\"no free port: {e}; check `ulimit -n` and leaked listeners (`ss -ltnp`)\");\n        std::process::exit(1);\n    }\n}","preventionTips":["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."],"tags":["network","port","resource-exhaustion","testing","rust","linera-base"],"backgroundTag":"port-exhaustion","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}