zed-industries/zed · error · Error::Internal
cannot unshare a project hosted by another user
Error message
cannot unshare a project hosted by another user
What it means
Thrown inside the unshare/delete-project transaction (crates/collab/src/db/queries/projects.rs:151): the caller's connection is compared against the project's recorded host_connection() — the connection that originally shared the project. Only the host connection (which returns early with Ok at projects.rs:147) or the server-admin path may proceed; any other connection, even the same user on a new connection, gets this error.
Source
Thrown at crates/collab/src/db/queries/projects.rs:151
&self,
project_id: ProjectId,
connection: ConnectionId,
) -> Result<TransactionGuard<(bool, Option<proto::Room>, Vec<ConnectionId>)>> {
self.project_transaction(project_id, |tx| async move {
let guest_connection_ids = self.project_guest_connection_ids(project_id, &tx).await?;
let project = project::Entity::find_by_id(project_id)
.one(&*tx)
.await?
.context("project not found")?;
let room = if let Some(room_id) = project.room_id {
Some(self.get_room(room_id, &tx).await?)
} else {
None
};
if project.host_connection()? == connection {
return Ok((true, room, guest_connection_ids));
}
Err(anyhow!("cannot unshare a project hosted by another user"))?
})
.await
}
/// Updates the worktrees associated with the given project.
pub async fn update_project(
&self,
project_id: ProjectId,
connection: ConnectionId,
worktrees: &[proto::WorktreeMetadata],
) -> Result<TransactionGuard<(Option<proto::Room>, Vec<ConnectionId>)>> {
self.project_transaction(project_id, |tx| async move {
let project = project::Entity::find_by_id(project_id)
.filter(
Condition::all()
.add(project::Column::HostConnectionId.eq(connection.id as i32))
.add(
project::Column::HostConnectionServerId.eq(connection.owner_id as i32),View on GitHub (pinned to bc538def45)
Solutions
- Send the unshare RPC from the same live connection that shared the project (the one recorded as host_connection_id/host_connection_server_id)
- If the host connection is gone, use the server-admin path or wait for the host-disconnect cleanup to remove the project rather than calling as another connection
- Check the returned boolean in the Ok path: host connections get Ok(true) meaning 'deleted now', other valid paths get Ok(false) meaning 'handled otherwise' — design callers around that contract
Defensive patterns
Strategy: validation
Validate before calling
// Only the connection that shared the project may unshare it
let is_host = project.host_connection_id == connection.id
&& project.host_connection_server_id == connection.owner_id;
if !is_host {
return Err(anyhow!("only the hosting connection can unshare"));
} Try / catch
match db.unshare_project(project_id, connection).await {
Ok((deleted, room, guests)) => Ok((deleted, room, guests)),
Err(err) if err.to_string().contains("hosted by another user") => {
Err(anyhow!("only the host connection can unshare this project"))
}
Err(err) => Err(err),
} Prevention
- Track which of your connections shared each project; unshare from that connection
- On reconnect (new ConnectionId), re-share to become host again before managing the share
- Respect the Ok(bool) contract: false means the server handled removal another way (e.g. host gone)
When it happens
Trigger: Calling unshare_project with a connection that is not the one that created the project — the host reconnected (new ConnectionId) and the old connection tries to clean up, a collaborator tries to unshare someone else's project, or the same user shares from a second device.
Common situations: Host client reconnects (connection id rotates) while the stale connection's teardown code runs; admin tooling assuming user-level ownership where the check is connection-level; race between host disconnect cleanup and explicit unshare.
Related errors
- can't update a project hosted by someone else
- guests cannot share projects
- not a collaborator on this project
- user is not a channel admin or channel does not exist
- user is not a channel member or channel does not exist
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/8b5cfa42a0f1ef5d.
Report an issue: GitHub.