{"record":{"id":"7737c07b783adfb2","repo":"github/copilot-sdk","slug":"failed-to-write-a-frame-to-the-in-process-runtime-7737c0","errorCode":null,"errorMessage":"failed to write a frame to the in-process runtime connection","messagePattern":"failed to write a frame to the in-process runtime connection","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/src/ffi.rs","lineNumber":190,"sourceCode":"    }\n}\n\n/// Write side of the FFI transport. Each frame is forwarded synchronously to\n/// the native `connection_write` export (native copies before returning).\npub(crate) struct FfiWriter {\n    shared: Arc<FfiShared>,\n}\n\nimpl AsyncWrite for FfiWriter {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        _cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<std::io::Result<usize>> {\n        if self.shared.write_frame(buf) {\n            Poll::Ready(Ok(buf.len()))\n        } else {\n            Poll::Ready(Err(std::io::Error::new(\n                std::io::ErrorKind::BrokenPipe,\n                \"failed to write a frame to the in-process runtime connection\",\n            )))\n        }\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        Poll::Ready(Ok(()))\n    }\n}\n\n/// Prepared FFI host. The cdylib is loaded process-globally and never unloaded\n/// (see [`load_library`]).\npub(crate) struct FfiHost {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/rust/src/ffi.rs#L172-L208","documentation":"This AsyncWrite impl for the in-process runtime connection returns a BrokenPipe io::Error when shared.write_frame(buf) reports the frame could not be queued — i.e. the runtime side of the in-process channel is gone (receiver dropped or shut down). The error surfaces to Tokio-based writers as a failed write on the connection, which typically tears the connection down with a BrokenPipe classification.","triggerScenarios":"Writing to the in-process runtime connection after the runtime task/handle has been dropped or shut down; issuing requests concurrently with runtime shutdown; poll_write invoked on a connection whose shared state already closed its receiver.","commonSituations":"Shutting down the embedded runtime while requests are still in flight; holding a client/connection across a runtime restart; a panic or early return in the runtime loop dropping the receiver while the caller keeps sending frames.","solutions":["Ensure the runtime is alive before writing: keep the runtime handle/join guard alive for the connection's lifetime and shut down clients first, runtime last.","Treat the BrokenPipe error as terminal: recreate the client/connection (restart the runtime) rather than retrying the same connection.","Drain in-flight requests and close connections gracefully before dropping/shutting down the runtime side.","Check application logs for a runtime-side panic or early exit that dropped the receiver unexpectedly."],"exampleFix":"// before\nlet conn = Connection::in_process(&runtime);\nspawn(worker(conn.clone()));\ndrop(runtime); // receiver gone; next write -> BrokenPipe\n\n// after\nlet conn = Connection::in_process(&runtime);\nlet worker = spawn(worker(conn.clone()));\nworker.await?; // drain requests first\ndrop(conn);\ndrop(runtime);","handlingStrategy":"try-catch","validationCode":"// Rust: check the runtime is still running before writing\nfn connection_usable(runtime: &RuntimeHandle) -> bool { runtime.is_running() }","typeGuard":"fn is_connected(conn: &Connection) -> bool { !conn.is_closed() }","tryCatchPattern":"match conn.send_frame(&buf).await {\n    Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => {\n        // receiver dropped: recreate runtime connection and retry once\n        let conn = reconnect()?;\n        conn.send_frame(&buf).await?;\n    }\n    other => other?,\n}","preventionTips":["Keep the runtime handle alive for as long as any connection exists (own it in a long-lived struct).","Shut down in order: clients/connections first, runtime last; await in-flight tasks before dropping the runtime.","Map BrokenPipe to a reconnect path instead of retrying on the same connection.","Investigate runtime-side panics that silently drop the receiver."],"tags":["rust","broken-pipe","ipc","async","shutdown"],"backgroundTag":"broken-pipe","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}