You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
HTTP bridge /query with multiple #h values silently narrows to the lexicographically smallest channel UUID — Workflows screen shows "No workflows yet" #5053
A POST /query filter with multiple #h values returns only events from the channel whose UUID sorts first; all other listed channels are silently ignored. The desktop Workflows screen (experimental) issues exactly this shape — one filter with all member-channel ids (getChannelsWorkflows) — so whenever the lexicographically smallest member channel contains no workflows, the screen shows "No workflows yet" even though workflows exist and run fine.
Reproduction (relay revision 6dbc946, self-hosted, single community)
Signed NIP-98 POST /query (agent key + x-auth-tag), body [{"#h":[…],"kinds":[30620]}]. Three channels: intake (1 workflow), servers (2 workflows), opdrachten (0 workflows). UUID order: opdrachten < intake < servers.
#
#h values
expected
returned
A
intake, servers
3
1 (intake only)
B
servers
2
2
C
servers, intake (reversed order)
3
1 (intake only)
E
servers, opdrachten (empty)
2
0
G
intake, welcome
1
1 (intake)
Order-independent (A vs C) → not "first in request wins" but "smallest UUID wins", consistent with iterating a sorted BTreeSet.
Root cause
crates/buzz-relay/src/handlers/req.rs, extract_channel_id_from_filter (single-filter variant, ~line 858): it returns the first parseable value of the #h tag set. nostr::Filter::generic_tags values are a BTreeSet<String>, so "first" = lexicographically smallest. build_event_query_from_filter then pins the SQL to channel_id = <that uuid>.
The multi-filter variant extract_channel_id_from_filters (~line 1029) has the correct guard ("Multiple distinct channel IDs — fall back to global"), but the HTTP bridge path (api/bridge.rs::query_events_authed → build_event_query_from_filter) uses the single-filter variant without that guard. The bridge's own extract_channel_from_filter (used for the access pre-check) does require len == 1, so the access check and the query builder disagree about the same filter.
Suggested fix
Give extract_channel_id_from_filter the same semantics as the plural variant: return None when the filter carries more than one distinct channel UUID. apply_access_scope_to_query then scopes the query to the caller's accessible channels (IN-list), and the existing per-event post-check (filters_match + accessible-channel check) keeps results correct.
Related UI papercut
WorkflowsView renders allWorkflowsQuery.data ?? [], so a failed or empty query is indistinguishable from "no workflows" — an error state would have made this much easier to spot.
Still reproduces on today's main with desktop 0.5.14 — and here is the SQL it emits
Confirming from a third setup, nine days on, with the one artifact none of the related issues carries: the statement the relay actually sends to Postgres.
Setup: desktop 0.5.14 on Windows 11, self-hosted relay from ghcr.io/block/buzz:main built 2026-08-15, single community, four member channels, one workflow living in the channel with the largest UUID.
The Workflows screen shows "No workflows yet". With log_statement = all on the database, that click produces:
SELECT id, pubkey, created_at, kind, tags, content, sig, received_at, channel_id
FROM events
WHERE community_id = $1AND deleted_at IS NULLAND channel_id = $2AND (channel_id IS NULLOR channel_id IN ($3, $4, $5, $6))
AND kind IN ($7)
ORDER BY created_at DESC, id ASCLIMIT $8 OFFSET $9
$2 = 47da111f-… <- one channel, the smallest UUID
$3..$6 = 47da111f-…, adafd400-…, d4ebe34a-…, daeb342d-… <- all four, as the desktop asked
$7 = 30620
Both channel_id predicates sit in the same statement, which makes the fix concrete: the access-scope IN list is already present and already confines the caller to their own channels, so dropping the singular channel_id = $2 push-down when the filter carries more than one #h value corrects the result set without widening access at all. The post-filter can only narrow, so nothing downstream can recover rows this predicate excluded — which is why the screen is empty rather than partially wrong.
On the cluster. This is reported three times (#4659 has the root cause and names the helper, this issue has the reproduction matrix, #4804 has the user-visible symptom), and six open PRs — #2452, #4393, #4446, #4624, #5307, #5339, the oldest from 2026-07-23 — every one of which touches crates/buzz-relay/src/handlers/req.rs. I have not reviewed their diffs, only confirmed they all patch that file. All six are currently MERGEABLE.
Posting this here rather than opening a seventh report, in case a fresh confirmation on the current build helps someone decide which of the existing patches to take.
Activity
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
docs: a workflow that runs but cannot be seen or stopped
docs: a workflow that runs but cannot be seen or stopped
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
artemtrofymenko commentedon Aug 15, 2026
Still reproduces on today's
mainwith desktop 0.5.14 — and here is the SQL it emitsConfirming from a third setup, nine days on, with the one artifact none of the related issues carries: the statement the relay actually sends to Postgres.
Setup: desktop 0.5.14 on Windows 11, self-hosted relay from
ghcr.io/block/buzz:mainbuilt 2026-08-15, single community, four member channels, one workflow living in the channel with the largest UUID.The Workflows screen shows "No workflows yet". With
log_statement = allon the database, that click produces:Both
channel_idpredicates sit in the same statement, which makes the fix concrete: the access-scopeINlist is already present and already confines the caller to their own channels, so dropping the singularchannel_id = $2push-down when the filter carries more than one#hvalue corrects the result set without widening access at all. The post-filter can only narrow, so nothing downstream can recover rows this predicate excluded — which is why the screen is empty rather than partially wrong.On the cluster. This is reported three times (#4659 has the root cause and names the helper, this issue has the reproduction matrix, #4804 has the user-visible symptom), and six open PRs — #2452, #4393, #4446, #4624, #5307, #5339, the oldest from 2026-07-23 — every one of which touches
crates/buzz-relay/src/handlers/req.rs. I have not reviewed their diffs, only confirmed they all patch that file. All six are currentlyMERGEABLE.Posting this here rather than opening a seventh report, in case a fresh confirmation on the current build helps someone decide which of the existing patches to take.
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID
fix(relay): stop multi-channel HTTP query from narrowing to one UUID