zed-industries/zed · error
failed to ring user
Error message
failed to ring user
What it means
Terminal error from the call_user handler when every attempt to deliver the IncomingCall request to the called user's connections fails (FuturesUnordered of peer requests yields no Ok). Before returning, the handler compensates: it marks the call failed via call_failed, broadcasts room_updated, and updates contacts, so the room state is rolled back consistently. Empty connection sets also land here because there is nothing to succeed.
Source
Thrown at crates/collab/src/rpc.rs:1803
return Ok(());
}
Err(_) => {
call_response.trace_err();
}
}
}
{
let room = session
.db()
.await
.call_failed(room_id, called_user_id)
.await?;
room_updated(&room, &session.peer);
}
update_user_contacts(called_user_id, &session).await?;
Err(anyhow!("failed to ring user"))?
}
/// Cancel an outgoing call.
async fn cancel_call(
request: proto::CancelCall,
response: Response<proto::CancelCall>,
session: MessageContext,
) -> Result<()> {
let called_user_id = UserId::from_proto(request.called_user_id);
let room_id = RoomId::from_proto(request.room_id);
{
let room = session
.db()
.await
.cancel_call(room_id, session.connection_id, called_user_id)
.await?;
room_updated(&room, &session.peer);
}View on GitHub (pinned to bc538def45)
Solutions
- Check the called user's online/presence state before placing the call and disable the button when offline
- Retry the call after a short delay — the user may have just come online; refresh presence between attempts
- Handle this error as 'unavailable' in the UI rather than a hard failure, since the room was already cleaned up
Example fix
// before
client.call_user(room_id, called_user_id, None).await?;
// after (presence gate + friendly failure)
if !presence.is_online(called_user_id) {
self.ui.show_toast("User is offline");
return Ok(());
}
if let Err(err) = client.call_user(room_id, called_user_id, None).await {
if err.to_string().contains("failed to ring user") {
self.ui.show_toast("Could not reach user; try again later");
return Ok(());
}
return Err(err);
} Defensive patterns
Strategy: retry
Validate before calling
// Presence gate before placing a call.
if !presence.is_online(called_user_id) {
self.ui.show_toast("User is offline");
return Ok(());
}
client.call_user(room_id, called_user_id, None).await?; Try / catch
for attempt in 0..3 {
match client.call_user(room_id, called_user_id, None).await {
Ok(_) => return Ok(()),
Err(err) if err.to_string().contains("failed to ring user") && attempt < 2 => {
smol::Timer::after(Duration::from_secs(2)).await; // user may come online
}
Err(err) => {
self.ui.show_toast("Could not reach user; try again later");
return Ok(()); // room state was already rolled back server-side
}
}
} Prevention
- Check presence/online state before showing the call button
- Retry with backoff — the target may reconnect at any moment
- Since the server already ran call_failed, resync room state after this error instead of assuming a live call
When it happens
Trigger: Called user is fully offline (no active connections); all their connections are on servers unreachable from this one; their clients reject/timeout the IncomingCall request; transient network partition during ring delivery.
Common situations: Calling someone whose app is closed; cross-server routing broken during departs; user signed out on all devices; mobile push-only users with no live socket.
Related errors
- cannot call a user who isn't a contact
- not a collaborator on this project
- banned users cannot invite
- could not find call to decline
- room does not exist or was already joined
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/b4ed8d1f02aa2cd8.
Report an issue: GitHub.