EpicGames/lore · error

Failed to open additional stream

Error message

Failed to open additional stream

What it means

This is a test-helper panic in Harness::open_stream: quinn's connection.open_bi() returned an Err (or the await was cancelled by connection death), and the test harness unwraps it with this message. It means the QUIC connection could not allocate a new bidirectional stream — almost always because the connection has already been closed or the peer refused the stream.

Solutions

  1. Check the server-side handler/factory for panics or early connection.close() before open_bi is called
  2. Ensure the client connection is still alive: inspect connection.close_reason() before opening streams
  3. Verify ALPN protocol strings match between server QuinnConfigBuilder and client crypto_config.alpn_protocols
  4. Reduce open_stream calls or confirm MAX_STREAMS transport limits permit another bidirectional stream

Example fix

// before
self.connection.open_bi().await.expect("Failed to open additional stream")
// after
match self.connection.open_bi().await {
    Ok(pair) => pair,
    Err(e) => panic!("Failed to open additional stream: {:?} (close reason: {:?})", e, self.connection.close_reason()),
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling open_stream
if harness.connection.close_reason().is_some() {
    panic!("connection already closed: {:?}", harness.connection.close_reason());
}

Type guard

fn is_conn_alive(conn: &quinn::Connection) -> bool { conn.close_reason().is_none() }

Try / catch

match self.connection.open_bi().await {
    Ok((s, r)) => (s, r),
    Err(quinn::ConnectionError::Closed(_) | quinn::ConnectionError::LocallyClosed) => panic!("connection closed before open_bi"),
    Err(e) => panic!("Failed to open additional stream: {e:?}"),
}

Prevention

When it happens

Trigger: Calling open_bi() after the server dropped the connection, after an idle timeout, when the peer's MAX_STREAMS credit is exhausted, or after connection.close()/QuinnServer::start failed so no connection was ever established.

Common situations: Server handler panicked and killed the connection before the test opened a second stream; ALPN mismatch or certificate rejection closed the connection during handshake; idle timeout between test steps; stream-count limits hit after many open_stream calls.

Related errors


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

Appendix: source

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

    ///
    /// Quinn's send and receive streams cannot be mocked, so exercising the stream handler needs
    /// a real server. The server, endpoint and connection are held because dropping any of them
    /// closes the stream.
    struct Harness {
        send: SendStream,
        recv: RecvStream,
        connection: quinn::Connection,
        _server: QuinnServer,
        _endpoint: Endpoint,
    }

    impl Harness {
        /// Open an additional stream on the same connection.
        async fn open_stream(&self) -> (SendStream, RecvStream) {
            self.connection
                .open_bi()
                .await
                .expect("Failed to open additional stream")
        }
    }

    /// Send a request asking the handler for `behaviour`.
    async fn request(send: &mut SendStream, behaviour: MockBehaviour, command_id: u32) {
        send.write(&CommandHeader::new(behaviour.opcode(), command_id, 0).to_bytes())
            .await
            .expect("Failed to write header");
        send.flush().await.expect("Failed flush");
    }

    /// 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)

View on GitHub (pinned to 074eb0b0d1)