loco-rs/loco · error

Failed to get local address

Error message

Failed to get local address

What it means

After binding, get_available_port calls listener.local_addr() to discover the OS-assigned port and .expect()s the result. If the local address cannot be retrieved the panic message is 'Failed to get local address'. This is rare — it usually indicates the socket was already closed or an OS-level socket error occurred.

Solutions

  1. Check ulimit -n / fd exhaustion if running many tests concurrently; raise the limit or reduce parallelism.
  2. Retry get_available_port() — the failure is typically transient/environmental.
  3. Verify the runtime environment supports getsockname on loopback sockets (gVisor/sandbox configs).
  4. Update the runtime/tokio and OS packages; check for known socket bugs in the container runtime.
Defensive patterns

Strategy: retry

Validate before calling

// precheck fd headroom
let free: i64 = std::fs::read_to_string("/proc/sys/fs/file-nr")
    .ok()
    .and_then(|s| s.split_whitespace().next().and_then(|n| n.parse().ok()))
    .unwrap_or(0);
assert!(free < 1_000_000, "file descriptors near exhaustion");

Try / catch

let port = (0..3).find_map(|_| get_available_port_safe()).unwrap_or_else(|| {
    panic!("could not obtain a local port after retries")
});

Prevention

When it happens

Trigger: Calling get_available_port() and having listener.local_addr() return Err: the listener was dropped/closed before the call, an OS socket error (fd exhaustion, EBADF), or an unusual network stack that cannot report the address.

Common situations: File-descriptor exhaustion under heavy parallel test load; custom network stacks (gVisor, some containers) with incomplete getsockname support; tokio runtime shutdown racing the helper; patched/virtualized loopback devices.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12). Data as JSON: /api/errors/da1b65f4edafa650. Report an issue: GitHub.

Appendix: source

Thrown at src/testing/request.rs:162

pub fn get_base_url_port(port: i32) -> String {
    format!("http://{TEST_BINDING_SERVER}:{port}/")
}

/// Returns a unique port number. Usually increments by 1 starting from 59126
///
/// # Panics
///
/// Will panic if binding to test server address fails or if getting the local address fails
pub async fn get_available_port() -> i32 {
    let addr = format!("{TEST_BINDING_SERVER}:0");
    let listener = TcpListener::bind(addr)
        .await
        .expect("Failed to bind to address");

    i32::from(
        listener
            .local_addr()
            .expect("Failed to get local address")
            .port(),
    )
}

/// Bootstraps test application with test environment hard coded.
///
/// # Example
///
/// The provided example demonstrates how to boot the test case with the
/// application context.
///
/// ```rust,ignore
/// use myapp::app::App;
/// use loco_rs::testing::prelude::*;
///
/// #[tokio::test]
/// async fn test_create_user() {
///     let boot = boot_test::<App>().await;

View on GitHub (pinned to 23639d1e36)