Skip to content
Fluxer API

Opcodes and close codes

An opcode is the number that names a Gateway payload. A close code is the number the Gateway sends when it ends a connection. Every value on this page belongs to the main Gateway alone. Gateway overview describes the connection and its state machine, and Client commands describes the payloads for these opcodes.

OpNameDirection
0DispatchServer to client
1HeartbeatBidirectional
2IdentifyClient to server
3Presence UpdateClient to server
4Voice State UpdateClient to server
5Voice Server PingReserved
6ResumeClient to server
7ReconnectServer to client
8Request Guild MembersClient to server
9Invalid Session1Server to client
10HelloServer to client
11Heartbeat ACKServer to client
12Gateway ErrorReserved
14Lazy RequestClient to server
15Request Guild CountsClient to server
16Request Channel Member CountsClient to server

1 Fluxer never sends Opcode 9 with d: true, so an Invalid Session is never an instruction to resume

OpPayloadWhen sent
0Event-specific dataFluxer sends a named event with t and a session sequence with s1
1The last processed sequence or null from the client, and null from the serverThe client sends on the advertised schedule. The server requests an immediate heartbeat once 90 per cent of the advertised interval has elapsed since the last acknowledgement2
2Identify objectThe client starts one authenticated session
3Presence Update objectThe client replaces its session presence
4Voice State Update objectThe client joins, moves, updates, or leaves voice
5Not implementedNever sent. A client that sends it is closed3
6Resume objectThe client restores a retained session4
7No d fieldThe Gateway asks the client to replace the connection and then closes with 40005
8Request Guild Members objectThe client requests bounded member chunks
9Literal falseThe session named by Resume could not be reached, the supplied seq is below the replay floor, or an established session ended6
10Object with heartbeat_intervalSent as the WebSocket is accepted, before any client payload is read
11No d fieldAcknowledges an accepted client heartbeat
12Not implementedNever sent. Errors reach the client as a Dispatch or a close frame
14Lazy Request objectThe client replaces bounded guild subscriptions
15Request Guild Counts objectThe client requests current guild count records
16Request Channel Member Counts objectThe client requests channel count records

1 Resumed has the session’s current sequence without advancing it, and a replayed Dispatch keeps the sequence it was first sent with

2 Answer a server heartbeat request immediately, in addition to the regular schedule

3 A client that sends Opcode 5 or 12 gets the same close as a client that sent an undefined opcode

4 Resume is accepted whether or not a session is already attached to the connection

5 Opcode 7 precedes the close when the Gateway node is draining, when the node transfers the session to another Gateway node, and when a Resume from a new socket displaces this one

6 After the frame, a socket whose session ended is unauthenticated. After a failed Resume, a socket that already held a session still holds it

The registry is complete. Opcode 13 and every value above 16 are undefined.

Fluxer resolves an inbound payload in this order.

  1. A payload that has no d reaches no command handler. Identify closes with 4005. Every other opcode, defined or not, closes with 4001.
  2. Heartbeat and Resume are handled whether or not a session is attached.
  3. Identify closes with 4005 when a session is already attached.
  4. Every remaining opcode closes with 4003 while no session is attached.
  5. With a session attached, Presence Update, Voice State Update, Request Guild Members, Lazy Request, Request Guild Counts, and Request Channel Member Counts are handled. Every other opcode, including a server opcode and an undefined value, closes with 4001.
CodeNameMeaning
4000Unknown errorDrain, an unclassified session creation error, or a Resume whose retained session could not be reached
4001Unknown opcodeThe opcode is undefined, is a server opcode, or the payload has no d
4002Decode errorThe payload size, compression stream, encoding, or command fields are invalid
4003Not authenticatedAn authenticated command arrived before Identify or Resume attached a session
4004Authentication failedThe token is invalid, or it does not own the retained session named by Resume
4005Already authenticatedIdentify arrived while a session was attached, or with no d
4007Invalid sequenceHeartbeat or Resume supplied a sequence outside the bounds that command accepts, as stated in Invalid sequence
4008Rate limitedA concurrent connection, connection payload, source IP payload, user payload, or session count budget was exceeded
4009Session timeoutMore than 45,000 ms elapsed since the last accepted heartbeat acknowledgement while the Gateway was awaiting one
4010Invalid shardThe Identify shard value is not a valid [shard_id, shard_count] pair1
4011Sharding requiredMore than 2,500 guilds resolve to one bot Gateway session2
4012Invalid API versionThe v connection parameter is absent or is not 1

1 shard_count is an integer from 1 to 16384, and shard_id is a non-negative integer below shard_count

2 The count is taken after the shard filter, so a bot clears it by identifying with a shard_count large enough that no shard owns more than 2,500 guilds

Code 4006 is unassigned, and no code above 4012 is defined. Event filtering describes how a client bounds the events its session receives.

CodeResumableResulting state
4000ConditionalClosed. A session attached to the connection remains recoverable1
4001ConditionalClosed. An already established session stays retained
4002ConditionalClosed. An already established session stays retained
4003NoClosed. No session exists for this connection
4004ConditionalClosed. Resume does not invalidate the session it named2
4005ConditionalClosed. A session established by an earlier Identify stays retained
4007No for that attemptClosed. The named session stays retained until its window expires
4008ConditionalClosed. An already established session stays retained
4009ConditionalClosed. An already established session stays retained
4010NoClosed. No session was created
4011NoClosed. No session was created
4012NoClosed before Hello. No session exists

1 A close that leaves a session without a socket begins a fresh 60,000 ms retention window, measured from the moment the socket ends. A session displaced by a Resume from a new socket is already attached to that socket and enters no window

2 A Resume that fails token verification leaves the named session in place for the rest of its retention window, so a later Resume with the owning token still recovers it. An Identify that fails token verification leaves nothing to recover

Resumable describes only whether an already established session can still be recovered with Resume. The 60,000 ms retention window and the bounded replay buffer described in Limits and rate limits still limit whether a Resume succeeds and what it replays.

Close 4007 follows one rule for Heartbeat and another for Resume.

Heartbeat tests the value’s type alone, and only once a session is attached. Before Identify or Resume attaches one, the Gateway accepts every d and answers with Opcode 11. With a session attached, the Gateway accepts a d that is null or any integer, and every other value closes with 4007. A sequence below the acknowledged sequence leaves that bound unchanged, and any other integer sets it and trims the replay buffer. A heartbeat that arrives in the short window between the session process ending and the socket noticing also closes with 4007.

Resume tests the bounds below and its seq must clear both.

  • The current sequence. A seq above the last sequence the session dispatched closes with 4007.
  • The acknowledged sequence. A seq below the last acknowledged sequence closes with 4007. A heartbeat with a higher sequence moves this bound.

A third bound, the replay floor, produces no close. It is the highest sequence the replay buffer has evicted. When a seq is inside both bounds but below the floor, the Gateway sends Opcode 9 with d: false and the named session stays retained until its window expires.

The Gateway sends an exact reason string with every application close.

ReasonCodeCause
Invalid API version4012The v connection parameter is absent or is not 1
Too many connections4008The source IP already holds 256 concurrent Gateway connections
Encode failed4002Hello could not be encoded1
Compression failed: zstd-stream4002Hello could not be compressed on a connection that negotiated zstd1
Payload too large4002An inbound message exceeded 4,096 bytes on the wire, or exceeded 4,096 bytes after decompression
Decompression failed4002An inbound compressed message could not be decompressed
Decode failed4002The payload is not valid JSON, or decodes to something other than an object
Invalid payload4002The decoded object has no op
Rate limited4008The connection, source IP, or user client payload budget was exceeded
Unknown opcode4001The opcode is undefined, is a server opcode, or the payload has no d
Not authenticated4003An authenticated command arrived before a session was attached
Already authenticated4005Identify arrived while a session was attached, or with no d
Invalid identify payload4002Identify is missing token or properties, or a field has the wrong type
Invalid shard4010The Identify shard value is not a valid [shard_id, shard_count] pair
Sharding required4011More than 2,500 guilds resolve to one bot session after the shard filter
Too many sessions4008The user already holds 100 live Gateway sessions2
Invalid token4004The Identify token is invalid, or the Resume token does not own the named session
Failed to start session4000Session creation returned a failure the Gateway does not classify3
Invalid resume payload4002Resume is not an object, or token or session_id is missing or is not a string, or seq is missing or is not an integer
Invalid sequence4007Heartbeat or Resume supplied a sequence outside the bounds stated in Invalid sequence
Invalid presence payload4002Presence Update is not an object, has no status, or has a status string that is not a known value
Session unavailable4000The retained session could not be reached while Resume was in progress
Session drain requested; reconnect to continue4000Opcode 7 was sent immediately before the close4
Heartbeat timeout4009No new heartbeat acknowledgement was accepted within 45,000 ms of the preceding acknowledgement

1 Both reasons are produced only while the Hello frame is being written. A later outbound frame that cannot be encoded or compressed is dropped and the connection stays open

2 A bot credential is bounded by the guild count that forces sharding, and this budget does not apply to it

3 The Gateway holds the Identify and retries it silently after a classified transient failure, so the connection stays open. That covers a paused rollout, a draining node, an ineligible account, an Identify rate limit, a saturated start budget, and a failed session RPC

4 The Gateway node is draining, the node is transferring the session to another Gateway node, or a Resume from a new socket displaced this one

Reason strings are stable wire values. A client branches on the code and MAY record the reason for diagnosis.

A transport can end with no Fluxer application close code, as happens on a network failure, an intermediary reset, and an ordinary 1000 or 1001 close. An established session remains available for 60,000 ms after the transport ends, and a later transport end starts a new 60,000 ms window. Neither the window length nor the bounded replay history grows.