block / block/buzz

Sending a message is refused with 'rate-limited: quota exceeded' after the client's own subscription burst

Open
#7,411 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

**Describe the bug**

Sending a chat message is refused with `rate-limited: quota exceeded; retry in Ns`, even though the user has sent nothing else.

The WebSocket admission budget is one bucket per pubkey covering both subscription requests (`REQ`) and published events (`EVENT`). A client that opens many channel subscriptions — at app start, or when replaying live subscriptions after a reconnect — spends that budget on its own bookkeeping, and the next message the user types is rejected. The bucket is also shared across devices, so a desktop client signed in as the same user draws from it too.

This became visible rather than new: an over-quota `EVENT` is now rejected on the `OK` channel, so the send fails with a reason. Previously the same rejection arrived as a bare `NOTICE` with no event id, and the send just timed out.

**Steps to reproduce**

1. Run a relay with the default rate limits.
2. Sign in as a user who is a member of many channels, on mobile and desktop at the same time.
3. Open the mobile app, or let it reconnect after a network change, so it resubscribes to every channel.
4. Type and send a message within the next few seconds.
5. The send fails with `rate-limited: quota exceeded; retry in Ns`.

**Expected behavior**

A user's own message should not be refused because the client spent the shared budget on its own subscriptions. Either give sends their own budget, or do not charge client-initiated sends against the subscription burst budget.

**Version and platform**

Buzz mobile on iOS, against a self-hosted relay built from `main`.

**Logs / screenshots**

Relay side, `buzz_admission_rejections_total{transport="websocket",reason="quota"}` climbs while the user is only reading and occasionally sending.

Closest existing report is #7019 (closed as not planned), where the desktop composer hung for the same reason before the rejection was made correlatable.

Contributor guide

Open the contributing guide

Research direction

Start by tracing the WebSocket admission accounting for client-initiated REQ and EVENT traffic, using the quota rejection metric and the behavior described in #7019 as context. Verify the shared per-pubkey bucket during subscription bursts and reconnects; done means a user's message is not refused because of the client's subscription bookkeeping, with the rejection behavior covered by relevant tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.