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

  1. Wait for the client's connected state before calling publishEvent().
  2. Retry publishEvent() after a short delay — connect() will re-establish the socket.
  3. Check that only one community/session is driving the client at a time.
  4. 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

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


AI-assisted analysis of block/buzz@dad5a33865 (2026-09-05). Data as JSON: /api/errors/8b946c20bf515fdd. Report an issue: GitHub.