block/buzz · error · Error
Read-only relay socket is not connected.
Error message
Read-only relay socket is not connected.
What it means
The read-only (observer) relay client checks, immediately before sending a publish, that the socket still belongs to the same connection generation and has a live wsId. If a reconnect/session change happened between connect() and the send, or wsId is null, it refuses to publish. This prevents writes through a stale or dead socket.
Source
Thrown at desktop/src/shared/api/readOnlyRelayClient.ts:118
this.publishes.delete(eventId);
}
this.onMessageChannel = null;
this.connectPromise = null;
}
async fetchEvents(filter: RelaySubscriptionFilter): Promise<RelayEvent[]> {
await this.connect();
return this.requestHistory(filter);
}
async publishEvent(event: RelayEvent): Promise<void> {
await this.connect();
const generation = this.generation;
await waitForRateLimit();
if (generation !== this.generation || this.wsId === null) {
throw new Error("Read-only relay socket is not connected.");
}
return new Promise<void>((resolve, reject) => {
const timeout = window.setTimeout(() => {
this.publishes.delete(event.id);
reject(new Error("Timed out publishing to observer relay."));
}, PUBLISH_TIMEOUT_MS);
this.publishes.set(event.id, { resolve, reject, timeout });
void this.sendRaw(["EVENT", event]).catch((error) => {
window.clearTimeout(timeout);
this.publishes.delete(event.id);
reject(
error instanceof Error
? error
: new Error("Failed to publish to observer relay."),
);View on GitHub (pinned to dad5a33865)
Solutions
- Wait for the client's connected state before calling publishEvent().
- Retry publishEvent() after a short delay — connect() will re-establish the socket.
- Check that only one community/session is driving the client at a time.
- Subscribe to connection-state changes and queue publishes while disconnected.
Example fix
// before
await client.publishEvent(event);
// after
await client.connect();
try { await client.publishEvent(event); }
catch (e) { if (isNotConnected(e)) await retryWithBackoff(() => client.publishEvent(event)); else throw e; } Defensive patterns
Strategy: retry
Validate before calling
// poll client readiness before publishing while (!client.isConnected()) await new Promise(r => setTimeout(r, 250));
Type guard
function isNotConnectedError(e: unknown): boolean { return e instanceof Error && e.message === 'Read-only relay socket is not connected.'; }
Try / catch
try { await client.publishEvent(ev); } catch (e) { if (isNotConnectedError(e)) await retryWithBackoff(() => client.publishEvent(ev)); else throw e; }
Prevention
- Await connect() and check connection state before publishing
- Queue publishes during community switches
- Use exponential backoff on retry, not tight loops
When it happens
Trigger: Calling publishEvent() while the observer socket is reconnecting, has been closed by a community switch, or the connection dropped after waitForRateLimit() yielded (generation changed or wsId became null).
Common situations: Publishing during a community switch; network drop mid-publish; rate-limit wait outlived the socket lifetime; publish attempted before the first successful connect completed.
Related errors
- Relay publish was superseded by a session change.
- repo announcement lost community serving lease: {error}
- Relay disconnected for community switch.
- Relay publish was superseded by a session change.
- setup-mode membership subscribe error: {e}
AI-assisted analysis of block/buzz@dad5a33865 (2026-09-05).
Data as JSON: /api/errors/8b946c20bf515fdd.
Report an issue: GitHub.