zed-industries/zed · error
already subscribed to entity
Error message
already subscribed to entity
What it means
subscribe_to_entity (crates/rpc/src/proto_client.rs:625) records a weak Entity handle under the pair (TypeId::of::<E>(), remote_id) so incoming messages for that remote entity are delivered to the local entity. The map allows one subscriber per (type, remote id); subscribing the same pair twice panics. There is no manual unsubscribe — entries clear only when the previous weak handle dies, so a still-live prior entity blocks a second subscribe.
Source
Thrown at crates/rpc/src/proto_client.rs:627
.payload
.remote_entity_id()
};
self.0
.client
.message_handler_set()
.lock()
.add_entity_message_handler(
message_type_id,
entity_type_id,
entity_id_extractor,
Arc::new(move |entity, envelope, _, cx| {
let entity = entity.downcast::<E>().unwrap();
let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
handler(entity, *envelope, cx).boxed_local()
}),
);
}
pub fn subscribe_to_entity<E: 'static>(&self, remote_id: u64, entity: &Entity<E>) {
let id = (TypeId::of::<E>(), remote_id);
let mut message_handlers = self.0.client.message_handler_set().lock();
if message_handlers
.entities_by_type_and_remote_id
.contains_key(&id)
{
panic!("already subscribed to entity");
}
message_handlers.entities_by_type_and_remote_id.insert(
id,
EntityMessageSubscriber::Entity {
handle: entity.downgrade().into(),
},
);
}View on GitHub (pinned to 9d272b0363)
Solutions
- Make the follow path idempotent at your layer: track (TypeId, remote_id) pairs you subscribed and reuse the existing entity instead of subscribing again.
- Ensure the old Entity and anything holding handles to it are dropped before subscribing a replacement; look for detached tasks or caches.
- Use the panic backtrace to find which follow flow runs twice and gate it.
- In tests, create fresh remote ids or drop prior entities before re-subscribing.
Example fix
// before client.subscribe_to_entity(remote_id, &new_entity); // old entity still alive // after: drop the previous handle before resubscribing drop(old_entity); client.subscribe_to_entity(remote_id, &new_entity);
Defensive patterns
Strategy: validation
Validate before calling
use std::any::TypeId;
// keep your own bookkeeping of live subscriptions:
if !self.subscribed.contains(&(TypeId::of::<E>(), remote_id)) {
self.client.subscribe_to_entity(remote_id, &entity);
self.subscribed.insert((TypeId::of::<E>(), remote_id));
} else {
// reuse the existing entity instead of re-subscribing
} Prevention
- Make follow/unfollow flows idempotent by tracking (type, remote_id) pairs.
- Drop prior Entity handles (and caches/tasks holding them) before subscribing replacements.
- Remember there is no manual unsubscribe — entries live until the weak handle dies.
- In tests, use fresh remote ids or explicitly drop old entities first.
When it happens
Trigger: Calling client.subscribe_to_entity(remote_id, &entity) for the same entity type and remote id while the previously subscribed handle is still alive — following the same remote participant/entity twice, or recreating a local entity for a remote id whose old Entity has not been dropped yet.
Common situations: Re-follow/unfollow races in collaboration; quickly re-opening a shared pane or entity view; a detached task or cache holding an Entity handle that keeps the first subscriber alive.
Related errors
- registered handler for the same message twice
- unsupported TOML value in .env.toml for key {}
- row out of range
- invalid display row {}
- blocking sender returned without value
AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20).
Data as JSON: /api/errors/78b958afdae12952.
Report an issue: GitHub.