astral-sh/ruff · error · anyhow::Error

Failed to send notification

Error message

Failed to send notification (method={method}): {error}

What it means

The server sends client notifications (publishDiagnostics, logMessage, ...) by pushing them onto an internal channel read by the main loop, which writes to the actual transport. If that channel is already closed — the main loop has exited because the transport broke or the server is shutting down — the send fails and this error is logged with the method name.

Solutions

  1. Treat it as expected noise during shutdown: restart the server and verify it reconnects cleanly
  2. If it recurs mid-session, check the transport (stderr/stdout pipes not blocked or closed early) and for earlier errors in the log that killed the main loop
  3. Reduce late work by letting in-flight background tasks drain before exiting (graceful shutdown)
  4. Update the server — shutdown-ordering improvements land regularly
Defensive patterns

Strategy: try-catch

Try / catch

// Rust: a failed notification send during teardown is not fatal
if let Err(e) = client.send_notification::<lsp_types::notification::PublishDiagnostics>(params) {
    tracing::warn!(%e, "dropping notification; main loop likely exited");
}

Prevention

When it happens

Trigger: A background task (e.g., a queued lint run) finishing after the client disconnected and the main loop exited; races during shutdown where diagnostics publishing overlaps server teardown; transport errors (broken pipe on stderr/stdout) killing the main loop first.

Common situations: Editor crashes or force-closes while background lint/format tasks are in flight; aggressive process supervision restarting the server; noisy logs during teardown that look like real failures.

Related errors


AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20). Data as JSON: /api/errors/3d278e56fdc21594. Report an issue: GitHub.

Appendix: source

Thrown at crates/ruff_server/src/session/client.rs:106

                format!("Failed to send request method={method}", method = R::METHOD)
            })?;

        Ok(())
    }

    /// Sends a notification to the client.
    pub(crate) fn send_notification<N>(&self, params: N::Params) -> crate::Result<()>
    where
        N: lsp_types::Notification,
    {
        let method = N::METHOD.to_string();

        self.client_sender
            .send(lsp_server::Message::Notification(Notification::new(
                method, params,
            )))
            .map_err(|error| {
                anyhow!(
                    "Failed to send notification (method={method}): {error}",
                    method = N::METHOD
                )
            })
    }

    /// Sends a notification without any parameters to the client.
    ///
    /// This is useful for notifications that don't require any data.
    #[expect(dead_code)]
    fn send_notification_no_params(&self, method: &str) -> crate::Result<()> {
        self.client_sender
            .send(lsp_server::Message::Notification(Notification::new(
                method.to_string(),
                Value::Null,
            )))
            .map_err(|error| anyhow!("Failed to send notification (method={method}): {error}"))
    }

View on GitHub (pinned to d1087a4b9e)