Skip to content

Desktop 0.4.26: after a relay reconnect the channel view can go permanently blank — resubscribe reuses the subscription ID, relay silently drops it, UI shows an empty channel with no error #3265

Description

@cmcgrabby-hue

Summary

On Buzz Desktop 0.4.26 (macOS 15.5, hosted relay wss://*.communities.buzz.xyz), a
channel intermittently renders empty or frozen at an old message while the relay
demonstrably holds newer events. Outgoing messages from the same app still publish
successfully. The connection indicator stays healthy. The only reliable recovery is a
full app quit + relaunch — reopening the channel, switching channels, and waiting do
nothing.

Because Desktop keeps no local message cache, a dead subscription is visually
indistinguishable from an empty channel. That is the part that makes this expensive:
there is no error, no banner, no retry affordance. A user reasonably concludes their
counterpart never replied.

Reproduction

Not deterministic on demand — it follows a network interruption (sleep/wake, Wi-Fi
change, relay blip). Observed several times over 2026-07-27/28. Sequence:

  1. Have a channel open with live traffic.
  2. Interrupt connectivity long enough for the relay socket to drop.
  3. Let Desktop reconnect on its own.
  4. Have another client publish a kind-9 into that channel.

Expected: the message appears.
Actual: nothing appears, indefinitely. Meanwhile:

$ buzz messages get --channel <uuid> | tail
# the relay has the message; it was stored and served on REQ

Sending from the blind Desktop window still works — the event publishes and other
clients receive it. So it is live fan-out to this client that is dead, not the
connection.

Diagnosis

Desktop links rust-nostr nostr-sdk 0.44.1 / nostr-relay-pool 0.44.1 (crate paths
present in the shipped binary). That library's reconnect path re-issues each stored
subscription with the same SubscriptionId — the strings Impossible to resubscribe., Removing subscription., Timeout reached for subscription, auto-closing. and Auto-closing subscription. are all present in the 0.4.26 binary,
alongside Buzz's own [relay_reconnect_hook] and Heartbeat: reconnected to ….

That behavior is correct per NIP-01 — a REQ reusing an existing subscription ID is
specified to replace that subscription, and reusing an ID after CLOSE is legal.

The problem is that the relay does not honor it. #3019 documents exactly this,
reproduced with minimal WebSocket clients:

A REQ reusing a sub ID that was CLOSEd earlier on the same connection is silently
ignored. […] Replacing (same-ID re-REQ) or CLOSEing overlapping subs kills delivery
for survivors.

Chain that together and the symptom follows directly:

socket drops
  → nostr-relay-pool auto-closes / re-REQs with the same SubscriptionId
  → relay silently discards the resubscribe (no NOTICE, no CLOSED)
  → transport is healthy, heartbeat logs "reconnected"
  → zero live events forever
  → UI renders an empty channel

A fresh process gets fresh subscription IDs, which is precisely why quit + relaunch is
the only thing that clears it.

I have not attached a packet trace to Desktop, so treat the causal chain as a strong
inference from (a) the linked library's documented resubscribe semantics, (b) the
strings in the shipped binary, and (c) the independently reproduced relay behavior in
#3019 — not as instrumented proof of this specific window.

Asks

The root-cause fix is relay-side and belongs to #3019 — the relay should honor a
same-ID REQ as a replacement per NIP-01. This issue is about the two things Desktop
can do regardless of when that lands:

1. Never render a silently-dead subscription as an empty channel. This is the
high-value one. If a subscription has been re-issued and no EOSE/events have arrived
within a timeout, surface it — a "reconnecting…" or "connection stale, click to
reload" state. Anything is better than a blank channel that looks like nobody has
spoken. Related but distinct: #3224 notes mobile lacks WebSocket stall detection;
desktop has transport-level detection but nothing at the subscription level, which
is where this fails.

2. Mitigate by generating a fresh subscription ID on reconnect. #3019's own
write-up names the client pattern that works reliably against the current relay: one
never-reused, never-replaced, never-CLOSEd subscription per channel. This is a
workaround for a relay bug rather than a correctness fix, so it is secondary to (1) —
but it would make the symptom disappear for every user on a hosted relay today,
without waiting on a relay deploy.

A cheap third option, if a cache is on the roadmap anyway: hydrating the channel view
from stored events on open would make a dead live-sub degrade to "stale" instead of
"empty."

Environment

  • Buzz Desktop 0.4.26 (latest release at time of filing), macOS 15.5 (Darwin 25.5.0), Apple silicon
  • Hosted relay, wss://<community>.communities.buzz.xyz
  • nostr-sdk 0.44.1, nostr-relay-pool 0.44.1, nostr 0.44.4 per binary strings
  • buzz-acp managed agents on the same machine keep responding normally through the
    outage — the agent harness resubscribes successfully where the UI does not, which is
    another signal the failure is in the Desktop subscription lifecycle rather than the
    network.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions