EpicGames/lore · error

Failed socket setup

Error message

Failed socket setup

What it means

serve_and_connect() binds an ephemeral UDP socket on 127.0.0.1:0 and then calls local_addr() to learn the chosen port before dropping the socket; this expect panics if local_addr() errors. It only fails if the OS reports the socket invalid, i.e. the bind or socket state is broken.

Solutions

  1. Retry the ephemeral bind if local_addr fails (transient OS issue)
  2. Check fd limits (ulimit -n) when running many tests in parallel
  3. Run outside sandboxed/privileged-restricted environments to rule out getsockname blocking
  4. If intermittent, restructure to keep the socket open and pass it to Quinn instead of bind/drop

Example fix

// before
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
let server_addr = socket.local_addr().expect("Failed socket setup");
// after
let socket = UdpSocket::bind("127.0.0.1:0").expect("bind failed");
let server_addr = socket.local_addr().expect("local_addr after successful bind failed");
Defensive patterns

Strategy: validation

Validate before calling

let socket = std::net::UdpSocket::bind("127.0.0.1:0").expect("ephemeral bind failed");
let server_addr = socket.local_addr().expect("local_addr failed");
assert!(server_addr.port() > 0);

Type guard

fn bound_addr(s: &std::net::UdpSocket) -> Option<std::net::SocketAddr> { s.local_addr().ok() }

Prevention

When it happens

Trigger: UdpSocket::bind succeeded but the fd was somehow closed/invalid by the time local_addr() runs (double-drop, fd exhaustion, sandboxed environment blocking getsockname).

Common situations: Running tests in restricted containers/sandboxes where socket metadata calls fail; file-descriptor exhaustion in large parallel test suites; rare OS-level socket errors.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/66b6d1bcfca9ccef. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/quic/stream_handler.rs:871

    /// Read one response header.
    async fn response(recv: &mut RecvStream) -> CommandHeader {
        let mut buffer = [0u8; 8];
        recv.read_exact(&mut buffer)
            .await
            .expect("Failed to read response");
        CommandHeader::from_bytes(&buffer)
    }

    /// Serve `factory` for `protocol` on a loopback endpoint and open a client stream to it.
    ///
    /// The client skips certificate verification and presents none of its own; the mTLS tests
    /// build their endpoints by hand because varying exactly that is what they test.
    async fn serve_and_connect(
        factory: Box<dyn StreamHandlerFactory>,
        protocol: &'static str,
    ) -> Harness {
        let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
        let server_addr = socket.local_addr().expect("Failed socket setup");
        drop(socket);

        let (cert_path, key_path, _) = server_certs().expect("Bad cert paths");
        let server = QuinnServer::start(
            QuinnConfigBuilder::new()
                .address(server_addr)
                .cert_file(cert_path)
                .pkey_file(key_path)
                .stream_handler_factory(factory)
                .build()
                .unwrap(),
        )
        .expect("Failed Quinn server start");

        let mut crypto_config = rustls::ClientConfig::builder()
            .dangerous()
            .with_custom_certificate_verifier(insecure_client_auth::SkipServerVerification::new())
            .with_no_client_auth();

View on GitHub (pinned to 074eb0b0d1)