BoundaryML/baml · error · anyhow
The connection with the client has been closed
Error message
The connection with the client has been closed
What it means
ClientSender holds a weak reference to the channel used to send messages to the LSP client. If the underlying sender has been dropped (the connection was shut down or its thread ended), upgrade() fails and send() bails with this error instead of panicking.
Solutions
- Drop or cancel background tasks when the connection shuts down so they don't attempt sends.
- Check connection liveness (or use a strong sender handle) before sending.
- Treat this as a benign shutdown race: log at debug level and ignore, rather than failing the task.
- Use a broadcast/closing channel pattern so senders observe disconnect gracefully.
Example fix
// before
let Some(sender) = self.weak_sender.upgrade() else {
anyhow::bail!("The connection with the client has been closed");
};
// after
let Some(sender) = self.weak_sender.upgrade() else {
log::debug!("Client connection closed; dropping outgoing message");
return Ok(());
}; Defensive patterns
Strategy: try-catch
Validate before calling
// sender-side liveness check before sending if (!clientConnection.isAlive()) return;
Type guard
function canSend(sender: Weak<ClientChannel>): boolean {
return sender.upgrade().is_some();
} Try / catch
if let Err(e) = sender.send(msg) {
log::debug!("send failed after disconnect: {e}"); // tolerate shutdown races
} Prevention
- Cancel background tasks on connection shutdown so they stop sending.
- Hold or re-check the strong sender before dispatching messages.
- Treat post-disconnect sends as benign; log at debug instead of failing.
- Test editor-close scenarios to catch late async sends.
When it happens
Trigger: Any server task (diagnostics updates, progress notifications, responses) attempts to send a message after the client connection was closed — e.g. a long-running analysis finishes after the editor disconnected.
Common situations: Editor closed while background diagnostics/analysis tasks are still running; server shutting down while queued responses are flushed; test harnesses dropping the client half of the channel early.
Related errors
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/5add9ae61db7d9df.
Report an issue: GitHub.
Appendix: source
Thrown at engine/language_server/src/server/connection.rs:172
std::mem::drop(self.receiver);
self.threads.into_iter().try_for_each(|t| t.join())?;
Ok(())
}
}
/// A weak reference to an underlying sender channel, used for communication with the client.
/// If the `Connection` that created this `ClientSender` is dropped, any `send` calls will throw
/// an error.
#[derive(Clone, Debug)]
pub struct ClientSender {
weak_sender: Weak<ConnectionSender>,
}
// note: additional wrapper functions for senders may be implemented as needed.
impl ClientSender {
pub(crate) fn send(&self, msg: lsp::Message) -> anyhow::Result<()> {
let Some(sender) = self.weak_sender.upgrade() else {
anyhow::bail!("The connection with the client has been closed");
};
sender.send(msg)?;
Ok(())
}
}
View on GitHub (pinned to bd85ce9dee)