WebSocket close codes: what 1000 to 1015 mean
A plain-language reference for the status codes a WebSocket close event can carry, and what each one does and does not tell you.
In short: 1000 is the only clean close. 1001 to 1011 come from the peer and name a reason. 1005, 1006, and 1015 are never sent on the wire; the browser reports them locally when no close frame arrived, and 1006 in particular says only that the connection dropped, not why.
Last updated
See a real close code
Run a WebSocket check from this browser
The NetOkay test opens an echo endpoint, sends one message, and closes with 1000. The result shows the close code your browser observed.
Run the WebSocket testClose codes 1000 to 1015
Codes 1000 to 1011 are defined in RFC 6455; 1012 to 1015 were added to the IANA registry afterwards. "Reserved for local use" means the code is set by the client library or browser, never received from the other end.
| Code | Name | What it means |
|---|---|---|
1000 |
Normal closure | The purpose of the connection was fulfilled and one side closed on purpose. This is the only code a browser check treats as a clean end. |
1001 |
Going away | The endpoint is leaving: a server shutting down, or a browser navigating away from the page. |
1002 |
Protocol error | A frame violated the WebSocket protocol; usually a bug in one implementation or a middlebox altering frames. |
1003 |
Unsupported data | The endpoint received a data type it cannot accept, for example binary when only text is handled. |
1004 |
Reserved | Not assigned. Should never be sent. |
1005 |
No status received | Reserved for local use: the close frame carried no code. Browsers report it when the peer closed without a status. |
1006 |
Abnormal closure | Reserved for local use: the connection ended without a close frame at all. A dropped TCP connection, a proxy timeout, a crashed process, and a blocked handshake all produce 1006. |
1007 |
Invalid payload | A text frame contained data that was not valid UTF-8, or a message did not match the declared type. |
1008 |
Policy violation | The endpoint refused the message for a policy reason it does not want to name; often used for authorization failures. |
1009 |
Message too big | A message exceeded the size the endpoint is willing to process. |
1010 |
Mandatory extension | The client expected the server to negotiate an extension and it did not. |
1011 |
Internal error | The server hit an unexpected condition that stopped it from completing the request. |
1012 |
Service restart | The server is restarting; clients may reconnect after a short wait. Registered with IANA, not part of the original RFC 6455 list. |
1013 |
Try again later | The server is overloaded or otherwise temporarily unavailable. Registered with IANA. |
1014 |
Bad gateway | A gateway or proxy received an invalid response from the upstream server. Registered with IANA. |
1015 |
TLS handshake failure | Reserved for local use: the connection closed because the TLS handshake failed, for example a certificate the client did not trust. |
Codes above 1015
- 3000 to 3999 are registered with IANA for libraries, frameworks, and public protocols. Their meaning depends on the software that defines them.
- 4000 to 4999 are for private use by applications. Your own server and client can agree on any meaning for them.
-
From browser JavaScript,
socket.close(code)accepts only 1000 or a value from 3000 to 4999; anything else throws.
What a close code can and cannot tell you
A code sent by the peer, such as 1008 or 1011, is a statement from that endpoint and is worth reading with its reason string. A locally generated code, above all 1006, only records that the connection ended without a close frame. It cannot distinguish a proxy idle timeout from a server crash, a firewall reset, or a network change, and it does not identify which hop dropped the connection. Treat 1006 as a prompt to look at both ends and every intermediary, not as a diagnosis.
The NetOkay echo endpoint itself closes with 1003 if it receives something other than text or binary data, 1009 if a message is larger than it accepts, and 1000 when its bounded time runs out.
Close code FAQ
Why do I only ever see 1006?
Because most failures happen before or outside the WebSocket protocol: a refused handshake, a dropped TCP connection, or a proxy that closed the socket without sending a close frame. The browser has nothing else to report. Check the HTTP handshake response and the server and proxy logs for the real reason.
Can I send my own close code?
Yes, but only 1000 or a code from 4000 to 4999 from browser code. Servers can send any registered code. Put the human-readable detail in the reason string, which is limited to 123 bytes.
Does 1006 mean my server crashed?
Not on its own. It means the connection ended without a close frame, which a crash causes, but so does a load balancer idle timeout or a laptop switching networks. If the server logs show a normal 1000 close that the client never received, look at the path between them.
Next: WebSocket connection failed: what to check walks through the failed stage, the original connection, and a retest.