astral-sh/ruff · error · anyhow::Error
Failed to send response for request
Error message
Failed to send response for request {id}: {error} What it means
Responses to client requests are queued onto an internal Event::SendResponse channel consumed by the main loop, which serializes them to the transport. If the main loop has already exited (client disconnected, transport failure, or shutdown race), sending the response fails and this error names the request ID whose answer could not be delivered.
Solutions
- Check earlier in the log for the underlying cause — the main loop exits for a reason (broken pipe, fatal error) and that is the real issue
- Restart the language server; a one-off occurrence during teardown is harmless
- If it happens mid-session, inspect the transport setup (stdout dedicated to LSP, logs on stderr) and client stability
- Update the server to pick up shutdown-ordering fixes
Defensive patterns
Strategy: try-catch
Try / catch
// Rust: respond best-effort; a closed channel means nobody is listening
if let Err(e) = client.respond(id, result) {
tracing::warn!(%e, "could not deliver response; client gone or shutting down");
} Prevention
- Check logs for the earlier error that killed the main loop — this failure is a symptom, not the cause
- Await in-flight requests client-side before disconnecting so responses are not orphaned
- Restart the server if these errors appear outside of teardown
When it happens
Trigger: A request handler finishing after the client vanished mid-request; transport write errors earlier in the log that terminated the main loop; shutdown racing an in-flight background request such as formatting.
Common situations: Editors killed while a slow format/hover request was outstanding; pipes closed prematurely by wrappers; supervisor-driven restarts where the old process logs send failures before dying.
Related errors
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/bd6805b259eaf9cf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/ruff_server/src/session/client.rs:147
/// and checked for cancellation (each request must have exactly one response).
pub(crate) fn respond<R>(
&self,
id: &RequestId,
result: crate::server::Result<R>,
) -> crate::Result<()>
where
R: serde::Serialize,
{
let response = match result {
Ok(res) => lsp_server::Response::new_ok(id.clone(), res),
Err(crate::server::Error { code, error }) => {
lsp_server::Response::new_err(id.clone(), code as i32, error.to_string())
}
};
self.main_loop_sender
.send(Event::SendResponse(response))
.map_err(|error| anyhow!("Failed to send response for request {id}: {error}"))
}
/// Sends an error response to the client for a given request ID.
///
/// The response isn't sent immediately. Instead, it's queued up in the main loop.
pub(crate) fn respond_err(
&self,
id: RequestId,
error: lsp_server::ResponseError,
) -> crate::Result<()> {
let response = lsp_server::Response {
id,
response_result: Err(error),
};
self.main_loop_sender
.send(Event::SendResponse(response))
.map_err(|error| anyhow!("Failed to send response: {error}"))View on GitHub (pinned to d1087a4b9e)