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:
- Have a channel open with live traffic.
- Interrupt connectivity long enough for the relay socket to drop.
- Let Desktop reconnect on its own.
- 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
Summary
On Buzz Desktop 0.4.26 (macOS 15.5, hosted relay
wss://*.communities.buzz.xyz), achannel 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:
Expected: the message appears.
Actual: nothing appears, indefinitely. Meanwhile:
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-sdk0.44.1 /nostr-relay-pool0.44.1 (crate pathspresent in the shipped binary). That library's reconnect path re-issues each stored
subscription with the same
SubscriptionId— the stringsImpossible to resubscribe.,Removing subscription.,Timeout reached for subscription, auto-closing.andAuto-closing subscription.are all present in the 0.4.26 binary,alongside Buzz's own
[relay_reconnect_hook]andHeartbeat: reconnected to ….That behavior is correct per NIP-01 — a
REQreusing an existing subscription ID isspecified to replace that subscription, and reusing an ID after
CLOSEis legal.The problem is that the relay does not honor it. #3019 documents exactly this,
reproduced with minimal WebSocket clients:
Chain that together and the symptom follows directly:
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
REQas a replacement per NIP-01. This issue is about the two things Desktopcan 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 arrivedwithin 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
wss://<community>.communities.buzz.xyznostr-sdk0.44.1,nostr-relay-pool0.44.1,nostr0.44.4 per binary stringsoutage — 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
#hfilters silently receive zero channel-scoped events