Skip to content

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 TEBHOS Gateway alone. Gateway overview describes the connection and its state machine, and Client commands describes the payloads for these opcodes.

Opcodes

Op Name Direction
0 Dispatch Server to client
1 Heartbeat Bidirectional
2 Identify Client to server
3 Presence Update Client to server
4 Voice State Update Client to server
5 Voice Server Ping Reserved
6 Resume Client to server
7 Reconnect Server to client
8 Request Guild Members Client to server
9 Invalid Session Server to client
10 Hello Server to client
11 Heartbeat ACK Server to client
12 Gateway Error Reserved
14 Lazy Request Client to server
15 Request Guild Counts Client to server
16 Request Channel Member Counts Client to server

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

Payload and when it is sent

Op Payload When sent
0 Event-specific data TEBHOS sends a named event with t and a session sequence with s. Resumed carries the current sequence without advancing it, and a replayed Dispatch keeps its original sequence
1 The last processed sequence or null from the client, and null from the server The client sends on the advertised schedule. The server requests an immediate heartbeat once 90 per cent of the interval has elapsed since the last acknowledgement
2 Identify object The client starts one authenticated session
3 Presence Update object The client replaces its session presence
4 Voice State Update object The client joins, moves, updates, or leaves voice
5 Not implemented Never sent. A client that sends it is closed like any undefined opcode
6 Resume object The client restores a retained session on a fresh socket
7 No d field The Gateway asks the client to replace the connection and then closes with 4000. Sent when the node drains, when it transfers the session to another node, and when a Resume from a new socket displaces this one
8 Request Guild Members object The client requests bounded member chunks
9 Literal false The session named by Resume could not be found, or an established session ended. Afterwards the socket is unauthenticated
10 Object with heartbeat_interval Sent as the WebSocket is accepted, before any client payload is read
11 No d field Acknowledges an accepted client heartbeat
12 Not implemented Never sent. Errors reach the client as a Dispatch or a close frame
14 Lazy Request object The client replaces bounded guild subscriptions
15 Request Guild Counts object The client requests current guild counts
16 Request Channel Member Counts object The client requests channel counts

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

TEBHOS resolves an inbound payload in this order.

  1. Heartbeat with a d key is handled whether or not a session is attached.
  2. Identify with d is handled only while no session is attached. Identify with a session attached, or with no d, closes with 4005.
  3. Resume with d is handled only while no session is attached. Resume with a session attached, or with no d, closes with 4005.
  4. Any other payload with no d, including Heartbeat, closes with 4001.
  5. Every remaining opcode closes with 4003 while no session is attached.
  6. 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.

Unknown server opcodes are forward compatible

A client SHOULD log an unknown opcode and ignore the frame, and MUST NOT close or reconnect solely because the server used an opcode newer than this registry.

Close codes

Code Name Meaning
4000 Unknown error Drain, an unclassified session creation error, or a Resume whose retained session could not be reached
4001 Unknown opcode The opcode is undefined, is a server opcode, or the payload has no d
4002 Decode error The payload size, compression stream, encoding, or command fields are invalid
4003 Not authenticated An authenticated command arrived before Identify or Resume attached a session
4004 Authentication failed The token is invalid, or it does not own the retained session named by Resume
4005 Already authenticated Identify or Resume arrived while a session was attached, or with no d
4007 Invalid sequence Heartbeat or Resume supplied a sequence outside the bounds that command accepts, as stated in Invalid sequence
4008 Rate limited A concurrent connection, connection payload, source IP payload, session payload, or session count budget was exceeded
4009 Session timeout More than 45,000 ms elapsed since the last accepted heartbeat acknowledgement while the Gateway was awaiting one
4010 Invalid shard The Identify shard value is not a valid [shard_id, shard_count] pair. shard_count is an integer from 1 to 16,384, and shard_id is a non-negative integer below it
4011 Sharding required More than 2,500 guilds resolve to one bot session after the shard filter. Identify with a larger shard_count
4012 Invalid API version The v connection parameter is absent or is not 1

Code 4006 is unassigned. Code 4013 (Ack backpressure) is reserved in the Gateway and is not currently sent. Event filtering describes how a client bounds the events its session receives.

Session outcome

Code Resumable Resulting state
4000 Conditional Closed. A session attached to the connection remains recoverable
4001 Conditional Closed. An already established session stays retained
4002 Conditional Closed. An already established session stays retained
4003 No Closed. No session exists for this connection
4004 Conditional Closed. A failed Resume does not invalidate the session it named. An Identify that fails leaves nothing to recover
4005 Conditional Closed. A session established by an earlier Identify or Resume stays retained
4007 No for that attempt Closed. The named session stays retained until its window expires
4008 Conditional Closed. An already established session stays retained
4009 Conditional Closed. An already established session stays retained
4010 No Closed. No session was created
4011 No Closed. No session was created
4012 No Closed before Hello. No session exists

A close that leaves a session without a socket begins a fresh 60,000 ms retention window, measured from the moment the socket ends. Resumable describes only whether an already established session can still be recovered with Resume. The retention window and the bounded replay buffer in Limits and rate limits still limit what a Resume replays.

Reconnecting unchanged reproduces 4004, 4010, and 4012

Change the token, the shard pair, or the version before you reconnect.

Invalid sequence

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 a session is attached, the Gateway accepts every d and answers with Opcode 11. With a session attached, it 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 the session cannot confirm within 5,000 ms, including one that arrives just as the session process ends, also closes with 4007.

Resume tests two bounds, 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.

Close reasons

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

Reason Code Cause
Invalid API version 4012 The v connection parameter is absent or is not 1
Too many connections 4008 The source IP already holds 256 concurrent Gateway connections
Encode failed 4002 Hello could not be encoded
Compression failed: zstd-stream 4002 Hello could not be compressed on a connection that negotiated zstd
Payload too large 4002 An inbound message exceeded 4,096 bytes on the wire, or 4,096 bytes after decompression
Decompression failed 4002 An inbound compressed message could not be decompressed
Decode failed 4002 The payload is not valid JSON, or decodes to something other than an object
Invalid payload 4002 The decoded object has no op
Rate limited 4008 The connection, source IP, or session payload budget was exceeded
Unknown opcode 4001 The opcode is undefined, is a server opcode, or the payload has no d
Not authenticated 4003 An authenticated command arrived before a session was attached
Already authenticated 4005 Identify or Resume arrived while a session was attached, or with no d
Invalid identify payload 4002 Identify is missing token or properties, or a field has the wrong type
Invalid shard 4010 The Identify shard value is not a valid [shard_id, shard_count] pair
Sharding required 4011 More than 2,500 guilds resolve to one bot session after the shard filter
Too many sessions 4008 The user already holds 100 live Gateway sessions
Invalid token 4004 The Identify token is invalid, or the Resume token does not own the named session
Failed to start session 4000 Session creation returned a failure the Gateway does not classify
Session start failed 4000 Session creation kept failing after its retries
Invalid resume payload 4002 Resume is not an object, or token or session_id is missing or not a string, or seq is missing or not an integer
Invalid sequence 4007 Heartbeat or Resume supplied a sequence outside the bounds in Invalid sequence
Invalid presence payload 4002 Presence Update is not an object, has no status, or has a status string that is not a known value
Invalid voice payload 4002 Voice State Update d is not an object
Session unavailable 4000 The retained session could not be reached while Resume was in progress
Session drain requested; reconnect to continue 4000 Opcode 7 was sent immediately before the close
Heartbeat timeout 4009 No new heartbeat acknowledgement was accepted within 45,000 ms of the preceding one

Encode failed and Compression failed: zstd-stream are produced only while the Hello frame is written. A later outbound frame that cannot be encoded or compressed is dropped and the connection stays open.

The Gateway holds an Identify and retries it silently after a classified temporary 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 or rate-limited session lookup.

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

Some refusals send nothing

A held or discarded Identify or Resume, an over-budget Presence Update, a dropped bounded request, and a rejected voice state update produce no close and no reason. Client commands states which command behaves that way.

Ordinary WebSocket closes

A transport can end with no TEBHOS 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.