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

  1. Drop or cancel background tasks when the connection shuts down so they don't attempt sends.
  2. Check connection liveness (or use a strong sender handle) before sending.
  3. Treat this as a benign shutdown race: log at debug level and ignore, rather than failing the task.
  4. 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

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)