zed-industries/zed · error
failed to send message: {error}
Error message
failed to send message: {error} What it means
request_dynamic registers a response channel, then sends the envelope either buffered (while disconnected) or unbuffered. If the underlying send fails - the outgoing channel was closed because the connection handler shut down (crates/remote/src/remote_client.rs:1964) - it logs 'failed to send message' and bails with the transport error.
Source
Thrown at crates/remote/src/remote_client.rs:1985
fn send<T: EnvelopedMessage>(&self, payload: T) -> Result<()> {
log::debug!("remote send name:{}", T::NAME);
self.send_dynamic(payload.into_envelope(0, None, None))
}
fn request_dynamic(
&self,
mut envelope: proto::Envelope,
type_name: &'static str,
use_buffer: bool,
) -> impl 'static + Future<Output = Result<proto::Envelope>> {
envelope.id = self.next_message_id.fetch_add(1, SeqCst);
let (tx, rx) = oneshot::channel();
let mut response_channels_lock = self.response_channels.lock();
response_channels_lock.insert(MessageId(envelope.id), tx);
drop(response_channels_lock);
let result = if use_buffer {
self.send_buffered(envelope)
} else {
self.send_unbuffered(envelope)
};
async move {
if let Err(error) = &result {
log::error!("failed to send message: {error}");
anyhow::bail!("failed to send message: {error}");
}
let response = rx.await.context("connection lost")?.0;
if let Some(proto::envelope::Payload::Error(error)) = &response.payload {
return Err(RpcError::from_proto(error, type_name));
}
Ok(response)
}
}
fn request_stream_dynamic(View on GitHub (pinned to 5a9b9558db)
Solutions
- Retry the request after the client reconnects (reconnect replays buffered envelopes where applicable)
- Check the connection state before issuing non-idempotent RPCs
- If sends fail persistently while supposedly connected, restart the remote server on the host
Defensive patterns
Strategy: retry
Validate before calling
// Gate RPCs on a live connection before issuing them
if !client.is_connected() {
client.wait_until_connected(cx).await; // or trigger/await reconnect
}
client.request(proto::Ping {}).await?; Try / catch
match client.request(payload.clone()).await {
Err(e) if e.to_string().contains("failed to send message") => {
// connection dropped mid-send: wait for reconnect, then re-issue once
client.wait_until_connected(cx).await;
client.request(payload).await
}
other => other,
} Prevention
- Route all requests through one supervisor that gates on connection state
- Make RPCs idempotent so a replay after reconnect is safe
When it happens
Trigger: Issuing any RPC request() at the moment the connection drops: the multiplex/connection task has exited and the outgoing sink is closed, so send_buffered() or send_unbuffered() returns Err.
Common situations: Network blip between send setup and flush; remote server process died; requests racing the disconnect/reconnect transition.
Related errors
- origin/main tip {main_sha[:12]} unavailable locally after fe
- {error}
- Timed out resyncing remote client
- Timed out pinging remote client
- build ids may only contain lowercase letters, numbers, '.',
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/ef5bff0123a83b34.
Report an issue: GitHub.