Skip to content

Limits and rate limits

Every Gateway connection has limits on what it sends, how long its session lives, how many commands it runs at once, and how much TEBHOS replays to it. Exceeding one closes the connection with a close code, discards the payload, or coerces the value. The close reason registry lists each exact reason.

These limits belong to the Gateway. HTTP API limits are described in Rate limits.

Transport and encoding

Framing owns the protocol version, the payload bound, and the compression contract. One inbound WebSocket message is limited to 4,096 bytes on the wire and to a further 4,096 bytes after decompression, and either bound closes with 4002 and reason Payload too large.

A compressed message that decompresses past 10 MiB closes with 4002 and reason Decompression failed.

Session lifecycle

Hello advertises a heartbeat interval of 41,250 ms. The Gateway checks the heartbeat state every 13,750 ms. When 37,125 ms (90 per cent of the interval) have elapsed since the last acknowledgement it sends Opcode 1, and a client answers it immediately. If no new acknowledgement is accepted before the elapsed time passes 45,000 ms, the connection closes with 4009 and reason Heartbeat timeout.

There is no separate authentication deadline. The heartbeat rule alone closes a socket that never authenticates.

A disconnected session remains resumable for 60,000 ms. Its presence is published as offline 5,000 ms after the socket drops. A successful Resume inside the window restores the status the session last selected.

One user account holds at most 100 live sessions. A further Identify closes with 4008 and reason Too many sessions. A bot credential is bounded by the guild ceiling below instead.

Shard counts run from 1 through 16,384. One bot shard covers at most 2,500 guilds. A malformed shard pair closes with 4010 for every credential. A bot assignment above the guild ceiling closes with 4011 and reason Sharding required. A user session is never refused for its guild count.

Session creation can be delayed

An Identify can remain pending with no response while the node drains, while the node is at capacity, while session starts are paused, while the account is outside the session rollout percentage, or while the API's session lookup is failing or rate limited. Continue heartbeating while waiting for Ready.

Session start limit

GET /gateway/bot returns a session start limit object for client compatibility. Its values are constants. Admission is actually bounded by the source IP Identify budget, the per-token session lookup budget, the per-user session count, the node's concurrent session-start capacity, and the rollout percentage.

Connection and command rate limits

The figures below are the defaults. An operator can disable these limits for a deployment.

Budget Limit When exceeded
Client payloads per WebSocket 600 in a rolling 60-second window Close with 4008 and reason Rate limited
Client payloads per authenticated session 600 in each fixed 60-second bucket Close with 4008 and reason Rate limited
Client payloads per source IP 6,000 in each fixed 60-second bucket Close with 4008 and reason Rate limited
Concurrent WebSockets per source IP 256 Close with 4008 and reason Too many connections before Hello
Identify and Resume attempts per source IP 300 in each fixed 60-second window The payload is discarded without a reply or close
Session lookups per token (API side) 20 per minute The Identify is held and retried in the background
Presence Update per WebSocket 5 in a rolling 20-second window The update is discarded without a close
Voice State Update per session 2 applied immediately per rolling second Later updates are queued
Complete member list requests per bot and guild 1 every 30 seconds Rate Limited Dispatch, no chunk

The session budget applies only after authentication. Every payload that passes the size and decoding checks counts, including heartbeats.

A discarded Identify or Resume is not retained or retried, so the client sends a new one itself once the budget recovers, before the heartbeat deadline closes the socket.

Voice State Update commands beyond the first two in a second enter a per-session queue that holds at most 64 commands and drains one command every 500 ms. A newer update replaces an older queued update for the same guild_id and connection_id pair, and a full queue discards its oldest entry before accepting the new one.

The complete-member-list budget is keyed by the account and the guild together, so reconnecting does not reset it.

Bounded commands

One WebSocket processes at most four bounded requests at once across Request Guild Members, Lazy Request, Request Guild Counts, and Request Channel Member Counts. Each request has a 10,000 ms deadline, after which it stops. Events already emitted are not retracted, so a command that emits its result in several events can deliver a partial result and then stop.

Request Guild Members keeps one replaceable pending request while another member request is active. The most recent further request replaces any earlier pending one and starts when the active request finishes.

A bounded command that finds all four slots occupied is dropped. There is no queue, no result event, and no close.

Request Guild Counts queries each guild with a 2,000 ms deadline under an overall 3,000 ms batch deadline. Request Channel Member Counts queries its guild with a 2,000 ms deadline. A guild that misses its deadline is omitted from the result.

Replay and backpressure

Resume history retains at most 4,096 Dispatch events and 16,777,216 bytes (16 MiB) of retained event data. When either bound is exceeded, the oldest retained events are dropped from the front of the buffer.

One Dispatch larger than 2,097,152 bytes (2 MiB) is delivered to the socket and never retained. The connection is not closed for it, so a client that resumes across such an event does not receive it again. Both byte bounds measure in-memory size, not wire bytes, so they are approximate.

Guild Members Chunk, Guild Sync, and Guild Member List Update are delivered live and never retained. A replay can therefore have sequence gaps even within its retention window.

A heartbeat with a sequence discards every retained Dispatch at or below that sequence and records it as the acknowledged sequence. A client MUST acknowledge only a sequence whose events it has finished processing. A heartbeat with null, and a heartbeat with a sequence below the acknowledged sequence, change nothing. Resume neither acknowledges nor evicts. A client that never heartbeats with a sequence keeps its full window until the count or byte bound evicts from the front.

Resume closes with 4007 on a seq below the acknowledged sequence, and on a seq above the session's current sequence.

Evictions are silent

TEBHOS keeps no replay floor. When the count or byte bound has evicted events above your seq, a Resume still succeeds and replays only the events that remain, with no Invalid Session and no marker for the missing range. A client that reconnects long after it fell behind should Identify again and rebuild its state from Ready instead of resuming.

Presence updates can be dropped under load without closing the connection.

Command payload limits

Command Limit Handling
Identify ignored_events 256 entries A longer array closes with 4002 and reason Invalid identify payload
Request Guild Members user_ids 100 IDs A longer array abandons the request
Request Guild Members limit 0 through 100 Clamped
Request Guild Members nonce 32 bytes An oversized nonce becomes null. It is echoed only when the request named exactly one guild
Lazy Request member list ranges 10 per channel, end at most 100,000, end - start at most 99 Invalid ranges are dropped and extra valid ranges are truncated
Lazy Request members 1,000 IDs per guild Invalid IDs are dropped and extra IDs are truncated
Request Guild Counts guild_ids 100 after deduplication Truncated
Request Channel Member Counts channel_ids 25 after deduplication Truncated
Count request nonce 1 through 64 bytes Omitted from the result when out of bounds

Client commands states the exact coercion or drop rule for each field.

Voice admission

Voice admission follows the enclosing guild, direct message, group direct message, channel, and permission rules. A refusal produces no event and closes nothing. Voice states the bounds in full.

A guild voice channel admits at most user_limit users, where 0 means unlimited. While any participant has a camera enabled, the channel admits at most 25 users in total, and a channel that already holds 25 users with cameras enabled refuses a further camera with VOICE_CAMERA_USER_LIMIT.

One user holds at most voice_connection_limit simultaneous voice connections in one guild voice channel. The field is part of the channel object, defaults to 5, and is clamped to 1 through 100. Pending connections that have not yet expired count against it.