block/buzz · error · Error
Relay disconnected for community switch.
Error message
Relay disconnected for community switch.
What it means
publishSessionEvent snapshots the session's publish ownership before the rate-limit wait and throws if ownership changed — the relay session was disconnected/replaced for a community switch while this publish was pending. It guarantees a publish never proceeds under a session that no longer owns the connection.
Source
Thrown at desktop/src/shared/api/relayEventPublisher.ts:26
ownership: () => number;
pendingEvents: Map<string, PendingEvent>;
send: (payload: unknown[], generation: number) => Promise<void>;
reconnect: () => Promise<number>;
normalizeError: (error: unknown, fallback: string) => Error;
recoverSocketFailure: (error: unknown, fallback: string) => Error;
};
/** Publish once, with one reconnect retry, without crossing session ownership. */
export async function publishSessionEvent(
session: PublishSession,
event: RelayEvent,
timeoutMessage: string,
sendErrorMessage: string,
): Promise<RelayEvent> {
const publishOwnership = session.ownership();
await waitForRateLimit();
if (publishOwnership !== session.ownership()) {
throw new Error("Relay disconnected for community switch.");
}
const publishGeneration = session.generation();
return new Promise<RelayEvent>((resolve, reject) => {
const timeout = window.setTimeout(() => {
session.pendingEvents.delete(event.id);
reject(new Error(timeoutMessage));
}, PUBLISH_TIMEOUT_MS);
const pendingEvent = { event, resolve, reject, timeout };
session.pendingEvents.set(event.id, pendingEvent);
void session
.send(["EVENT", event], publishGeneration)
.catch(async (error) => {
// A disconnect may already have rejected this operation while the send
// was in flight. Its late failure must not reset the replacement session.
if (
publishOwnership !== session.ownership() ||View on GitHub (pinned to dad5a33865)
Solutions
- Delay or cancel publishes during a community switch and re-dispatch on the new session.
- Catch and retry after the switch completes (fresh ownership/generation).
- Gate send buttons on community-switch-in-progress state.
- Check for multiple components publishing through a session being torn down.
Example fix
// before
await publishSessionEvent(session, event, ...);
// after
try { await publishSessionEvent(session, event, ...); }
catch (e) {
if (isSuperseded(e)) await publishSessionEvent(session, event, ...); // retry on new session
else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (session.switchInProgress()) await session.switchComplete; // hold publishes until stable
Type guard
function isSupersededError(e: unknown): boolean { return e instanceof Error && e.message.includes('superseded by a session change'); }
Try / catch
try { await publishEvent(ev); } catch (e) { if (isSupersededError(e) || e.message.includes('community switch')) await republishOnCurrentSession(ev); else throw e; }
Prevention
- Disable send actions while a community switch is in progress
- Re-dispatch queued events after the new session is ready
- Never reuse a session reference after teardown
When it happens
Trigger: Calling publishEvent() (via publishSessionEvent) while a community switch is disconnecting/replacing the session; waitForRateLimit() yields and, on resume, the ownership token no longer matches.
Common situations: User switches communities while a message/media event is publishing; logout during publish; rapid community switching with queued events.
Related errors
- repo announcement lost community serving lease: {error}
- Read-only relay socket is not connected.
- Relay publish was superseded by a session change.
- Relay publish was superseded by a session change.
- an admin cannot ban or time out a community owner or fellow
AI-assisted analysis of block/buzz@dad5a33865 (2026-09-05).
Data as JSON: /api/errors/48ba00db81a671c5.
Report an issue: GitHub.