{"record":{"id":"8cffbd6c0a70a6c8","repo":"EpicGames/lore","slug":"failed-to-write-header","errorCode":null,"errorMessage":"Failed to write header","messagePattern":"Failed to write header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lore-server/src/quic/stream_handler.rs","lineNumber":849,"sourceCode":"        _server: QuinnServer,\n        _endpoint: Endpoint,\n    }\n\n    impl Harness {\n        /// Open an additional stream on the same connection.\n        async fn open_stream(&self) -> (SendStream, RecvStream) {\n            self.connection\n                .open_bi()\n                .await\n                .expect(\"Failed to open additional stream\")\n        }\n    }\n\n    /// Send a request asking the handler for `behaviour`.\n    async fn request(send: &mut SendStream, behaviour: MockBehaviour, command_id: u32) {\n        send.write(&CommandHeader::new(behaviour.opcode(), command_id, 0).to_bytes())\n            .await\n            .expect(\"Failed to write header\");\n        send.flush().await.expect(\"Failed flush\");\n    }\n\n    /// Read one response header.\n    async fn response(recv: &mut RecvStream) -> CommandHeader {\n        let mut buffer = [0u8; 8];\n        recv.read_exact(&mut buffer)\n            .await\n            .expect(\"Failed to read response\");\n        CommandHeader::from_bytes(&buffer)\n    }\n\n    /// Serve `factory` for `protocol` on a loopback endpoint and open a client stream to it.\n    ///\n    /// The client skips certificate verification and presents none of its own; the mTLS tests\n    /// build their endpoints by hand because varying exactly that is what they test.\n    async fn serve_and_connect(\n        factory: Box<dyn StreamHandlerFactory>,","sourceCodeStart":831,"sourceCodeEnd":867,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/quic/stream_handler.rs#L831-L867","documentation":"This panic comes from the test helper request(): SendStream::write returned Err and the harness expects it with this message. Writing to a QUIC send stream fails when the connection has been closed, the stream has been stopped/reset by the peer, or the send window cannot be advanced.","triggerScenarios":"Calling send.write() on a stream whose connection was closed by the peer, after recv-side issued StopSending causing the stream to reset, or after writing to an already-finished stream.","commonSituations":"Server handler called stop/reset on the stream before reading the header; server process dropped the connection mid-test; test writes a header after the handler already returned and closed the stream.","solutions":["Inspect the returned WriteError (ClosedStream vs ConnectionLost vs Stopped) to pick the fix","Ensure the server handler keeps the recv stream open until it has read the full header","Check the server didn't close the connection due to a handler panic (check server logs/JoinHandles)","Reorder the test so request() is called before any step that stops or finishes the stream"],"exampleFix":"// before\nsend.write(&CommandHeader::new(behaviour.opcode(), command_id, 0).to_bytes()).await.expect(\"Failed to write header\");\n// after\nif let Err(e) = send.write(&CommandHeader::new(behaviour.opcode(), command_id, 0).to_bytes()).await {\n    panic!(\"Failed to write header: {:?}, connection reason: {:?}\", e, connection.close_reason());\n}","handlingStrategy":"try-catch","validationCode":"// ensure the stream is still writable\nif harness.connection.close_reason().is_some() {\n    panic!(\"cannot write header: connection closed\");\n}","typeGuard":"fn stream_writable(conn: &quinn::Connection) -> bool { conn.close_reason().is_none() }","tryCatchPattern":"match send.write(&header.to_bytes()).await {\n    Ok(_) => (),\n    Err(quinn::WriteError::Stopped(code)) => panic!(\"peer stopped stream: {code}\"),\n    Err(e) => panic!(\"Failed to write header: {e:?}\"),\n}","preventionTips":["Never stop/reset the server-side stream before the client finishes writing the header","Check server handler panics first when writes start failing","Keep header size in sync with the reader's expectations","Hold server handles for the full test lifetime"],"tags":["quic","rust","test-harness","io"],"backgroundTag":"broken-pipe","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}