EpicGames/lore · error

Failed to write data

Error message

Failed to write data

What it means

A `.expect("Failed to write data")` panic in the `test_command` QUIC test when writing the remainder of the header plus repository and token bytes to the send half fails. By this point the partial header was already accepted, so the failure means the stream or connection died between the flush and the data write.

Solutions

  1. Inspect the server task for a panic while handling the partial (4-byte) header
  2. Check QUIC connection idle timeout configuration versus the test's sleep durations
  3. Print the underlying write error to see if it is a stream reset (`Stopped`) vs connection error
  4. Ensure the repository/token byte lengths match what the server's header declares

Example fix

// before
harness.send.write(data.to_vec().as_slice()).await.expect("Failed to write data");
// after
harness.send.write(data.to_vec().as_slice()).await
    .unwrap_or_else(|e| panic!("data write failed (stream stopped by peer?): {e:?}"));
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure declared payload length matches data actually written
assert_eq!(header.payload_len(), data.len() as u64, "payload length mismatch");

Try / catch

if let Err(e) = harness.send.write(data.to_vec().as_slice()).await {
    panic!("data write failed: {e:?}");
}

Prevention

When it happens

Trigger: `harness.send.write(data.to_vec().as_slice()).await` returns Err — the peer reset the stream while the server processed the partial header, the connection was closed, or the send half was shut down by the harness.

Common situations: Server-side header parsing panics/exits on the partial-header case and closes the stream; QUIC idle/timeout settings firing during the test's sleeps; resource exhaustion on CI causing the connection to drop.

Related errors


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

Appendix: source

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

            // Split across two writes, so the server has to buffer a partial header.
            harness
                .send
                .write(&header_bytes[..4])
                .await
                .expect("Failed to write header");
            harness.send.flush().await.expect("Failed flush");
            tokio::time::sleep(Duration::from_millis(1)).await;

            let mut data = bytes::BytesMut::new();
            data.extend_from_slice(&header_bytes[4..]);
            data.extend_from_slice(repository.as_bytes());
            data.extend_from_slice(token_bytes);

            harness
                .send
                .write(data.to_vec().as_slice())
                .await
                .expect("Failed to write data");
            harness.send.flush().await.expect("Failed flush");

            assert_eq!(
                header.response_success(0),
                response(&mut harness.recv).await
            );

            harness.send.finish().expect("Failed to finish stream");
        }))
        .await
        .expect("Test task failed");
    }

    #[tokio::test]
    async fn server_with_mtls_rejects_clients_without_certs() {
        let (immutable_store, mutable_store, execution) =
            test_store_create().await.expect("Failed to create store");
        lore_spawn!(LORE_CONTEXT.scope(execution.clone(), async move {

View on GitHub (pinned to 074eb0b0d1)