zed-industries/zed · error · Error::Internal

can't update a project hosted by someone else

Error message

can't update a project hosted by someone else

What it means

Thrown by the worktree diagnostic-summary update handler (crates/collab/src/db/queries/projects.rs:533): after loading the project, the sending connection is compared to project.host_connection() and mismatches. Only the host connection may push diagnostic summaries for the shared project's worktrees.

Source

Thrown at crates/collab/src/db/queries/projects.rs:533

    /// Updates the diagnostic summary for the given connection.
    pub async fn update_diagnostic_summary(
        &self,
        update: &proto::UpdateDiagnosticSummary,
        connection: ConnectionId,
    ) -> Result<TransactionGuard<Vec<ConnectionId>>> {
        let project_id = ProjectId::from_proto(update.project_id);
        let worktree_id = update.worktree_id as i64;
        self.project_transaction(project_id, |tx| async move {
            let summary = update.summary.as_ref().context("invalid summary")?;

            // Ensure the update comes from the host.
            let project = project::Entity::find_by_id(project_id)
                .one(&*tx)
                .await?
                .context("no such project")?;
            if project.host_connection()? != connection {
                return Err(anyhow!("can't update a project hosted by someone else"))?;
            }

            // Update summary.
            worktree_diagnostic_summary::Entity::insert(worktree_diagnostic_summary::ActiveModel {
                project_id: ActiveValue::set(project_id),
                worktree_id: ActiveValue::set(worktree_id),
                path: ActiveValue::set(summary.path.clone()),
                language_server_id: ActiveValue::set(summary.language_server_id as i64),
                error_count: ActiveValue::set(summary.error_count as i32),
                warning_count: ActiveValue::set(summary.warning_count as i32),
            })
            .on_conflict(
                OnConflict::columns([
                    worktree_diagnostic_summary::Column::ProjectId,
                    worktree_diagnostic_summary::Column::WorktreeId,
                    worktree_diagnostic_summary::Column::Path,
                ])
                .update_columns([

View on GitHub (pinned to bc538def45)

Solutions

  1. Only the sharing client should send diagnostic-summary updates; clients in participant mode must not forward them
  2. On reconnect, re-share (or take over hosting) before emitting further updates — a new connection id fails the host check
  3. Drop queued updates captured under the previous connection instead of replaying them on the new one
Defensive patterns

Strategy: validation

Validate before calling

// Only the host connection emits diagnostic summaries
if project.host_connection_id != connection.id
    || project.host_connection_server_id != connection.owner_id
{
    return Ok(()); // not host: drop the update
}

Try / catch

match db.update_worktree_diagnostic_summary(project_id, connection, update).await {
    Ok(v) => Ok(v),
    Err(err) if err.to_string().contains("hosted by someone else") => {
        log::warn!("diagnostic update rejected: not the host connection");
        Ok(Vec::new())
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: A guest/collaborator connection in the room (or the host's second connection) sends UpdateWorktreeDiagnosticSummary for a project it did not share; the host reconnected with a new ConnectionId and the old connection emits a late summary update.

Common situations: Guest clients mirroring the host's diagnostic events and wrongly forwarding them; retry queues flushing after a reconnect assigned a new connection id; test harnesses replaying captured updates with an arbitrary connection.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/d75d208f6b6868b4. Report an issue: GitHub.