skip to content

A WebSocket client needed an extension the server did not return: which close code does it send, and why does no server send it?

level: middleimportance: nice to knowfreq 24%

answer

  1. declining is allowed
  2. the client is the one left holding it
  3. a close code, not an HTTP status
  4. the server refuses earlier instead
  5. 1010 for a missing extension

basics

~20 s

The client sends WebSocket close code 1010, which means it expected the server to negotiate one or more extensions and the server did not. A server never needs it: it can refuse the opening handshake instead of accepting and then closing.

solid answer

~50 s

Declining an extension is legal, so a server that simply omits it from the `101 Switching Protocols` response has done nothing wrong — the connection establishes normally. If the client genuinely required that extension, the decision is now the client's, and it closes the established connection with **close code 1010**, whose defined meaning is that the endpoint expected the server to negotiate one or more extensions and the server did not. The code is documented as one a **server** does not use, and the reason is structural: a server that will not proceed can fail the opening handshake with an HTTP error response, before any socket exists to carry a close frame. The asymmetry is worth holding on to — a *declined* extension establishes a connection and then closes it, while an *unoffered* extension in the response means the handshake never completed at all.

go deeper

for a junior

Know that a server may decline an extension the client asked for, and that this is a normal outcome rather than an error — the socket opens and simply runs without it.

for a middle

Name close code 1010, say that the client sends it on the established connection, and explain that a server has no need for it because it can refuse the opening handshake before any socket exists.

for a senior

Separate the two failures cleanly: a declined extension ends in a close frame, an unoffered one ends with no connection at all. Then treat a 1010 as a configuration fault rather than something to reconnect through.

for a principal

Deciding that a client cannot run without a given extension is a commitment across your whole fleet; failing loudly at connect time is only better than degrading if someone is actually watching for it.

## Two different failures that look alike Extension negotiation can go wrong in two ways, and they end very differently. | What happened | Is it legal? | How it ends | |---|---|---| | The server omitted an extension the client offered | yes — declining is permitted | the connection establishes; the client may close it with 1010 | | The server returned an extension the client never offered | no — a rule violation | the client fails the WebSocket connection while validating the response, so no connection is established and no close frame is sent | Candidates routinely merge these, which produces the wrong answer to both. The first is a **policy** decision made by an application that cannot work without the extension. The second is a **protocol** violation caught before the socket exists. ## What 1010 says, and who says it Close code 1010 has one defined meaning: the endpoint is terminating the connection because it expected the server to negotiate one or more extensions, and the server did not return them. Three details are worth stating precisely: - It is sent by the **client**, on an established connection, in a Close control frame — the WebSocket close status is a two-byte value in the close frame, not an HTTP status. - The close reason is the place to say *which* extension was missing; the code alone does not carry that. - The specification notes that **a server does not use this code**, and explains why: a server that is unwilling to proceed can fail the opening handshake instead. That last point is the whole question. The server holds the earlier position in the exchange. It reads the client's offer, and if it cannot or will not proceed without something, it never sends the `101 Switching Protocols` response at all — it answers the HTTP request with an error. There is nothing to close, because nothing was opened. The client has no such option: by the time it discovers the omission, it has already received the 101, and the only exit it owns is the close handshake. ## Which close code, and which namespace This is a WebSocket close code, not an HTTP status code and not any other protocol's error value. It lives in the range the WebSocket protocol defines for close frames, alongside the codes for normal closure, for going away, for a protocol error, and for a policy violation. Two neighbours are worth separating from it: - **A protocol error code** is for a peer that broke the rules. Declining an extension breaks no rule, so it is the wrong code here. - **A policy violation code** is the generic "your behaviour is not acceptable to me" code, and it is what applications reach for when the missing thing was a *subprotocol* rather than an extension — because the specification defines no dedicated code for that case. ## What a strict client should do 1. Read the `Sec-WebSocket-Extensions` field on the 101 response and compare it against what was offered. 2. If it names anything that was not offered, fail the connection outright — do not attempt a close frame, because no connection was established. 3. If a genuinely required extension is missing, close the established connection with 1010 and put the extension name in the reason. 4. Treat that outcome as a configuration fault, not a transient one. Reconnecting immediately will negotiate exactly the same result, because nothing about the server changed. ## Why any of this matters in practice Most clients do not require an extension at all — compression is an optimisation, and running without it is merely slower. The case where 1010 is the right answer is narrow: a client that cannot function unless a specific extension is in force, and would rather fail loudly at connect time than run in a mode it was not designed for. That narrowness is the point of the question. It tests whether you know that **declining is legal**, that the protocol distinguishes a permitted outcome from a violation, and that the two ends of a WebSocket handshake have structurally different exits: one can refuse before the socket exists, the other can only close after it does.

  • What if the missing thing was a required subprotocol rather than an extension?
    The protocol defines no dedicated close code for that. The connection still establishes, and a client that cannot proceed closes it with a policy-violation code or one from the ranges reserved for application use, naming the problem in the close reason.
  • Should the client retry immediately after closing with 1010?
    No. The server's answer was a deliberate configuration, not a transient failure, so an immediate reconnect negotiates the same result and adds load. Treat it as a fault to surface, and retry only on a long backoff in case the server's configuration changes.
  • Why does an unoffered extension in the 101 response not produce a close code at all?
    Because checking the response is part of completing the handshake. When that check fails, the WebSocket connection is never established, so there is no open socket on which a close frame could be sent — the client simply abandons the connection.

saying these in an interview costs you the question

  • Says a server sends 1010 when a client omits an extension it wanted
  • Treats a declined extension as a protocol violation by the server
  • Confuses the WebSocket close code with an HTTP status code
  • Thinks a client must abort when the server declines compression
  • Believes an unoffered extension in the response is answered with a close frame